diff --git a/.gitignore b/.gitignore index 0a23e9c6a..4e9e7f229 100755 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,13 @@ core build install log +docs/_site .vscode +.jekyll-cache *.weights *.csv .gitignore +.jekyll-cache meters_to_gnss_degrees.py data/maps/grand_loop/carlaMapAdjust3.xodr data/maps/grand_loop/grand_loop_medium.pcd diff --git a/Dockerfile b/Dockerfile index e4a3912e5..18c30c4b7 100755 --- a/Dockerfile +++ b/Dockerfile @@ -44,7 +44,7 @@ RUN pip install -v -e . && mim download mmsegmentation --config pspnet_r50-d8_51 # ARG PYTORCH # ARG CUDA # ARG MMCV -# RUN pip3 install -U openmim && mim install mmcv-full +RUN pip3 install -U openmim && mim install mmcv-full # # Install MMSegmentation # RUN git clone https://github.com/open-mmlab/mmsegmentation.git /mmsegmentation @@ -66,13 +66,12 @@ RUN pip install -v -e . && mim download mmsegmentation --config pspnet_r50-d8_51 COPY ./docker/install-dependencies.sh /opt/docker_ws/ RUN apt update && apt install -y software-properties-common && /opt/docker_ws/install-dependencies.sh - COPY ./docker/install-pip-dependencies.sh /opt/docker_ws/ RUN /opt/docker_ws/install-pip-dependencies.sh && rm -rf /var/lib/apt/lists/* COPY ./docker ./opt/docker_ws -# # Copy and build our modified version of CycloneDDS, important ROS middleware +# Copy and build our modified version of CycloneDDS, important ROS middleware COPY ./src/tools/cyclonedds /opt/cyclone_ws/cyclonedds COPY ./src/tools/rmw_cyclonedds /opt/cyclone_ws/rmw_cyclonedds WORKDIR /opt/cyclone_ws @@ -85,13 +84,17 @@ RUN apt update && echo "net.core.rmem_max=8388608\nnet.core.rmem_default=8388608 ################# # Code here should either be moved to install-dependencies.sh or removed # before each major release. -RUN apt update && apt install -y ros-foxy-octomap octovis ros-foxy-pcl-ros ros-foxy-tf2-eigen +#RUN apt update && apt install -y ros-foxy-octomap octovis ros-foxy-pcl-ros ros-foxy-tf2-eigen RUN pip3 install shapely==2.0.0 -RUN pip3 install --upgrade scipy networkx +RUN pip3 install --upgrade scipy networkx # https://stackoverflow.com/questions/66669735/ubuntu-20-04-cant-find-pcl-because-of-incorrect-include-directory-after-install RUN mkdir /lib/x86_64-linux-gnu/cmake/pcl/include && ln -s /usr/include/pcl-1.10/pcl /lib/x86_64-linux-gnu/cmake/pcl/include/pcl + +RUN apt update && apt install -y ros-foxy-joy-linux ros-foxy-pcl-ros minicom ros-foxy-rosbridge-server ros-foxy-image-transport ros-foxy-async-web-server-cpp + +RUN pip3 install scikit-image ################# # END CLEANUP # ################# @@ -100,4 +103,10 @@ ENV ROS_VERSION 2 WORKDIR /navigator COPY ./docker/entrypoint.sh /opt/entrypoint.sh + +# RUN useradd -ms /bin/bash docker +RUN usermod -a -G dialout root +RUN usermod -a -G tty root +# USER docker + ENTRYPOINT [ "/opt/entrypoint.sh" ] \ No newline at end of file diff --git a/README.md b/README.md index eb3097d82..4135cae84 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -[](https://nova-utd.github.io/navigator) +[](https://nova-utd.github.io/navigator) Navigator is a simple, modular, open-source autonomous driving stack. It's developed by Nova, an undergraduate research team at UT Dallas. For docs, visit [our documentation site](https://nova-utd.github.io/navigator). -For info about our group, Nova, visit our [group site](https://nova-utd.github.io). \ No newline at end of file +For info about our group, Nova, visit our [group site](https://nova-utd.github.io). diff --git a/data/carla-0.9.13-py3.7-linux-x86_64.egg b/data/carla-0.9.13-py3.7-linux-x86_64.egg deleted file mode 100755 index e8d2cf817..000000000 Binary files a/data/carla-0.9.13-py3.7-linux-x86_64.egg and /dev/null differ diff --git a/data/carla.urdf b/data/carla.urdf index 8e35db7d8..9c2f32f4b 100755 --- a/data/carla.urdf +++ b/data/carla.urdf @@ -27,7 +27,7 @@ - + diff --git a/data/carla_objects.json b/data/carla_objects.json index 25b08f702..64e70ec7e 100644 --- a/data/carla_objects.json +++ b/data/carla_objects.json @@ -9,32 +9,37 @@ { "type": "vehicle.tesla.model3", "id": "hero", - "spawn_point": {"x": 17.8, "y": -192.0, "z": 1.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0}, + "spawn_point": {"x": 21.7, "y": -191.9, "z": 1.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0}, "sensors": [ { - "type": "sensor.camera.rgb", - "id": "birds_eye", - "spawn_point": {"x": 0.85, "y": 0.0, "z": 25.0, "roll": 0.0, "pitch": 90.0, "yaw": 0.0}, - "image_size_x": 1024, - "image_size_y": 512, - "fov": 120.0 + "type": "sensor.pseudo.tf", + "id": "tf", + "spawn_point": {"x": 0.0, "y": 0.0, "z": 0.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0} }, { "type": "sensor.camera.rgb", "id": "rgb_left", - "spawn_point": {"x": 0.7, "y": 0.15, "z": 1.88, "roll": 0.0, "pitch": 0.0, "yaw": 60.0}, - "image_size_x": 1024, - "image_size_y": 512, - "fov": 120.0 + "spawn_point": {"x": 0.7, "y": 0.15, "z": 1.88, "roll": 0.0, "pitch": 0.0, "yaw": 70.0}, + "image_size_x": 800, + "image_size_y": 600, + "fov": 70.0 + }, + { + "type": "sensor.camera.rgb", + "id": "rgb_center", + "spawn_point": {"x": 0.7, "y": -0.15, "z": 1.88, "roll": 0.0, "pitch": 0.0, "yaw": 0.0}, + "image_size_x": 800, + "image_size_y": 600, + "fov": 70.0 }, { "type": "sensor.camera.rgb", "id": "rgb_right", - "spawn_point": {"x": 0.7, "y": -0.15, "z": 1.88, "roll": 0.0, "pitch": 0.0, "yaw": -60.0}, - "image_size_x": 1024, - "image_size_y": 512, - "fov": 120.0 + "spawn_point": {"x": 0.7, "y": -0.15, "z": 1.88, "roll": 0.0, "pitch": 0.0, "yaw": -70.0}, + "image_size_x": 800, + "image_size_y": 600, + "fov": 70.0 }, { "type": "sensor.lidar.ray_cast", @@ -70,10 +75,17 @@ "noise_alt_stddev": 0.000005, "noise_lat_stddev": 0.000005, "noise_lon_stddev": 0.000005, "noise_alt_bias": 0.0, "noise_lat_bias": 0.0, "noise_lon_bias": 0.0 }, + { + "type": "sensor.other.gnss", + "id": "true_gnss", + "spawn_point": {"x": 0.0, "y": 0.0, "z": 0.00}, + "noise_alt_stddev": 0.0, "noise_lat_stddev": 0.0, "noise_lon_stddev": 0.0, + "noise_alt_bias": 0.0, "noise_lat_bias": 0.0, "noise_lon_bias": 0.0 + }, { "type": "sensor.other.imu", "id": "imu", - "spawn_point": {"x": 0.7, "y": 0.0, "z": 0.28, "roll": 0.0, "pitch": 0.0, "yaw": 0.0}, + "spawn_point": {"x": 0.0, "y": 0.0, "z": 0.0, "roll": 0.0, "pitch": 0.0, "yaw": 0.0}, "noise_accel_stddev_x": 0.001, "noise_accel_stddev_y": 0.001, "noise_accel_stddev_z": 0.015, "noise_gyro_stddev_x": 0.001, "noise_gyro_stddev_y": 0.001, "noise_gyro_stddev_z": 0.001, "noise_gyro_bias_x": 0.0, "noise_gyro_bias_y": 0.0, "noise_gyro_bias_z": 0.0 diff --git a/data/fastrtps.xml b/data/fastrtps.xml new file mode 100644 index 000000000..c32500959 --- /dev/null +++ b/data/fastrtps.xml @@ -0,0 +1,71 @@ + + + + + + + test + UDPv4 + 5500 + true + + + + + + + test + + false + + + + + + + + SYNCHRONOUS + + + PREALLOCATED_WITH_REALLOC + + + + + PREALLOCATED_WITH_REALLOC + + + + + + + SYNCHRONOUS + + + + + + + PREALLOCATED_WITH_REALLOC + + + + + + + ASYNCHRONOUS + + + + + + + PREALLOCATED_WITH_REALLOC + + + + + PREALLOCATED_WITH_REALLOC + + + \ No newline at end of file diff --git a/data/hail_bopp.urdf b/data/hail_bopp.urdf index d85604278..0abdf262f 100755 --- a/data/hail_bopp.urdf +++ b/data/hail_bopp.urdf @@ -70,7 +70,7 @@ - + @@ -89,13 +89,13 @@ - + - - + + - + @@ -114,9 +114,9 @@ - + - + diff --git a/lb_map.xml b/data/maps/town12.xodr similarity index 100% rename from lb_map.xml rename to data/maps/town12.xodr diff --git a/data/mcl.rviz b/data/mcl.rviz index b2b840232..cd9258546 100644 --- a/data/mcl.rviz +++ b/data/mcl.rviz @@ -1,19 +1,17 @@ Panels: - Class: rviz_common/Displays - Help Height: 138 + Help Height: 0 Name: Displays Property Tree Widget: Expanded: - /Global Options1 + - /Status1 - /TF1/Frames1 - - /LiDAR1/Filtered LiDAR1 - - /Path1 - - /Grids1 - - /Grids1/Drivable Area1 - - /Grids1/Current Occupancy1 - - /Path2 + - /Cameras1 + - /Cameras1/RGB Center1 + - /Pose1/Topic1 Splitter Ratio: 0.5 - Tree Height: 454 + Tree Height: 440 - Class: rviz_common/Selection Name: Selection - Class: rviz_common/Tool Properties @@ -30,7 +28,7 @@ Panels: Visualization Manager: Class: "" Displays: - - Alpha: 0.5 + - Alpha: 0.30000001192092896 Cell Size: 1 Class: rviz_default_plugins/Grid Color: 85; 170; 255 @@ -41,11 +39,11 @@ Visualization Manager: Name: Grid Normal Cell Count: 0 Offset: - X: 0 + X: 10 Y: 0 Z: 0 Plane: XY - Plane Cell Count: 10 + Plane Cell Count: 150 Reference Frame: Value: true - Angle Tolerance: 0.10000000149011612 @@ -65,7 +63,7 @@ Visualization Manager: Scale: 1 Value: true Value: true - Enabled: true + Enabled: false Keep: 100 Name: Smoothed GNSS Position Tolerance: 0.10000000149011612 @@ -85,10 +83,10 @@ Visualization Manager: History Policy: Keep Last Reliability Policy: Reliable Value: /odometry/gnss_processed - Value: true - - Alpha: 1 + Value: false + - Alpha: 0.30000001192092896 Class: rviz_default_plugins/RobotModel - Collision Enabled: false + Collision Enabled: true Description File: "" Description Source: Topic Description Topic: @@ -122,21 +120,66 @@ Visualization Manager: TF Prefix: "" Update Interval: 0 Value: true - Visual Enabled: true + Visual Enabled: false - Class: rviz_default_plugins/TF - Enabled: false + Enabled: true Frame Timeout: 15 Frames: All Enabled: false - Marker Scale: 100 + base_link: + Value: false + hero: + Value: false + hero/gnss: + Value: false + hero/imu: + Value: false + hero/lidar: + Value: false + hero/rgb_center: + Value: true + hero/rgb_left: + Value: false + hero/rgb_right: + Value: false + hero/semantic_lidar: + Value: false + hero/true_gnss: + Value: false + map: + Value: false + model_link: + Value: false + Marker Scale: 5 Name: TF Show Arrows: true Show Axes: true Show Names: false Tree: - {} + hero: + base_link: + model_link: + {} + hero/gnss: + {} + hero/imu: + {} + hero/lidar: + {} + hero/rgb_center: + {} + hero/rgb_left: + {} + hero/rgb_right: + {} + hero/semantic_lidar: + {} + hero/true_gnss: + {} + map: + {} Update Interval: 0 - Value: false + Value: true - Class: rviz_default_plugins/Marker Enabled: true Name: Marker @@ -163,17 +206,17 @@ Visualization Manager: Color: 255; 255; 255 Color Transformer: Intensity Decay Time: 0 - Enabled: true + Enabled: false Invert Rainbow: false Max Color: 255; 255; 255 - Max Intensity: 0.9899380803108215 + Max Intensity: 0.9759141206741333 Min Color: 0; 0; 0 - Min Intensity: 0.7262483239173889 + Min Intensity: 0.712297797203064 Name: Filtered LiDAR Position Transformer: XYZ Selectable: true Size (Pixels): 3 - Size (m): 0.30000001192092896 + Size (m): 0.10000000149011612 Style: Flat Squares Topic: Depth: 5 @@ -183,7 +226,7 @@ Visualization Manager: Value: /lidar/filtered Use Fixed Frame: true Use rainbow: true - Value: true + Value: false - Alpha: 1 Autocompute Intensity Bounds: true Autocompute Value Bounds: @@ -217,7 +260,40 @@ Visualization Manager: Use Fixed Frame: true Use rainbow: true Value: false - Enabled: true + - Alpha: 1 + Autocompute Intensity Bounds: false + Autocompute Value Bounds: + Max Value: 8.593732833862305 + Min Value: -0.0016748905181884766 + Value: true + Axis: Z + Channel Name: c + Class: rviz_default_plugins/PointCloud2 + Color: 255; 255; 255 + Color Transformer: RGB8 + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Max Intensity: 13 + Min Color: 0; 0; 0 + Min Intensity: 0 + Name: Semantic LiDAR + Position Transformer: XYZ + Selectable: true + Size (Pixels): 3 + Size (m): 0.30000001192092896 + Style: Flat Squares + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /lidar/semantic + Use Fixed Frame: true + Use rainbow: true + Value: true + Enabled: false Name: LiDAR - Alpha: 1 Autocompute Intensity Bounds: true @@ -234,9 +310,9 @@ Visualization Manager: Enabled: true Invert Rainbow: false Max Color: 255; 255; 255 - Max Intensity: 0.015573475509881973 + Max Intensity: 0.03333333507180214 Min Color: 0; 0; 0 - Min Intensity: 0.0007359013543464243 + Min Intensity: 0.03333333507180214 Name: Particles Position Transformer: XYZ Selectable: true @@ -256,20 +332,20 @@ Visualization Manager: Buffer Length: 1 Class: rviz_default_plugins/Path Color: 25; 255; 0 - Enabled: true + Enabled: false Head Diameter: 0.30000001192092896 Head Length: 0.20000000298023224 - Length: 0.30000001192092896 - Line Style: Lines + Length: 10 + Line Style: Billboards Line Width: 0.5 - Name: Path + Name: Rough Route Offset: X: 0 Y: 0 Z: 0 Pose Color: 255; 85; 255 - Pose Style: None - Radius: 0.029999999329447746 + Pose Style: Axes + Radius: 1 Shaft Diameter: 0.10000000149011612 Shaft Length: 0.10000000149011612 Topic: @@ -277,8 +353,8 @@ Visualization Manager: Durability Policy: Volatile History Policy: Keep Last Reliability Policy: Reliable - Value: /route/rough_path - Value: true + Value: /planning/rough_route + Value: false - Class: rviz_common/Group Displays: - Class: rviz_default_plugins/Image @@ -309,6 +385,20 @@ Visualization Manager: Reliability Policy: Reliable Value: /carla/hero/rgb_left/image Value: true + - Class: rviz_default_plugins/Image + Enabled: true + Max Value: 1 + Median window: 5 + Min Value: 0 + Name: RGB Center + Normalize Range: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /carla/hero/rgb_center/image + Value: true - Class: rviz_default_plugins/Image Enabled: true Max Value: 1 @@ -324,7 +414,7 @@ Visualization Manager: Value: /carla/hero/rgb_right/image Value: true - Class: rviz_default_plugins/Image - Enabled: true + Enabled: false Max Value: 1 Median window: 5 Min Value: 0 @@ -335,10 +425,10 @@ Visualization Manager: Durability Policy: Volatile History Policy: Keep Last Reliability Policy: Reliable - Value: /semantic/left_mono - Value: true + Value: /semantic/left + Value: false - Class: rviz_default_plugins/Image - Enabled: true + Enabled: false Max Value: 1 Median window: 5 Min Value: 0 @@ -349,8 +439,8 @@ Visualization Manager: Durability Policy: Volatile History Policy: Keep Last Reliability Policy: Reliable - Value: /semantic/right_mono - Value: true + Value: /semantic/right + Value: false Enabled: true Name: Cameras - Class: rviz_common/Group @@ -359,7 +449,7 @@ Visualization Manager: Class: rviz_default_plugins/Map Color Scheme: raw Draw Behind: true - Enabled: true + Enabled: false Name: Drivable Area Topic: Depth: 5 @@ -374,12 +464,12 @@ Visualization Manager: Reliability Policy: Reliable Value: /grid/drivable_updates Use Timestamp: true - Value: true + Value: false - Alpha: 0.699999988079071 Class: rviz_default_plugins/Map - Color Scheme: raw + Color Scheme: map Draw Behind: true - Enabled: true + Enabled: false Name: Current Occupancy Topic: Depth: 5 @@ -394,6 +484,146 @@ Visualization Manager: Reliability Policy: Reliable Value: /grid/occupancy/current_updates Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz_default_plugins/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Predicted Occupancy + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/predictions_combined + Update Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/predictions_combined_updates + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz_default_plugins/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Route Distance + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/route_distance + Update Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/route_distance_updates + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz_default_plugins/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Steering Cost + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/cost + Update Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/cost_updates + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz_default_plugins/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Speed Cost + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/speed_cost + Update Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/speed_cost_updates + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz_default_plugins/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Junction Occupancy + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/junction_occupancy + Update Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/junction_occupancy_updates + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz_default_plugins/Map + Color Scheme: map + Draw Behind: false + Enabled: false + Name: Junctions + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/junction + Update Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/junction_updates + Use Timestamp: false + Value: false + - Alpha: 0.699999988079071 + Class: rviz_default_plugins/Map + Color Scheme: map + Draw Behind: false + Enabled: true + Name: Stateful Junction + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/stateful_junction + Update Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /grid/stateful_junction_updates + Use Timestamp: false Value: true Enabled: true Name: Grids @@ -401,19 +631,19 @@ Visualization Manager: Buffer Length: 1 Class: rviz_default_plugins/Path Color: 255; 0; 0 - Enabled: true + Enabled: false Head Diameter: 2 Head Length: 5 Length: 10 Line Style: Billboards - Line Width: 4 - Name: Path + Line Width: 1 + Name: Smooth Route Offset: X: 0 Y: 0 Z: 0 Pose Color: 255; 85; 255 - Pose Style: Axes + Pose Style: None Radius: 1 Shaft Diameter: 2 Shaft Length: 10 @@ -422,12 +652,116 @@ Visualization Manager: Durability Policy: Volatile History Policy: Keep Last Reliability Policy: Reliable - Value: /route/smooth_path + Value: /planning/smooth_route + Value: false + - Class: rviz_default_plugins/Camera + Enabled: false + Image Rendering: background and overlay + Name: Camera + Overlay Alpha: 0.5 + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /carla/hero/rgb_right/image + Value: false + Visibility: + Cameras: + "": true + Value: true + Grid: true + Grids: + "": true + Value: true + LiDAR: + "": true + Value: true + Marker: true + Particles: true + Path: true + Pose: true + RobotModel: true + Rough Route: true + Smooth Route: true + Smoothed GNSS: true + TF: true + Value: true + Zoom Factor: 1 + - Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Class: rviz_default_plugins/Pose + Color: 255; 25; 0 + Enabled: false + Head Length: 0.30000001192092896 + Head Radius: 0.10000000149011612 + Name: Pose + Shaft Length: 2 + Shaft Radius: 2 + Shape: Arrow + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /planning/goal_pose + Value: false + - Class: rviz_default_plugins/Marker + Enabled: true + Name: Marker + Namespaces: + {} + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /visuals/airbags + Value: true + - Alpha: 1 + Buffer Length: 1 + Class: rviz_default_plugins/Path + Color: 25; 255; 0 + Enabled: true + Head Diameter: 0.30000001192092896 + Head Length: 0.20000000298023224 + Length: 0.30000001192092896 + Line Style: Billboards + Line Width: 0.5 + Name: Path + Offset: + X: 0 + Y: 0 + Z: 0 + Pose Color: 255; 85; 255 + Pose Style: None + Radius: 0.029999999329447746 + Shaft Diameter: 0.10000000149011612 + Shaft Length: 0.10000000149011612 + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /planning/path + Value: true + - Class: rviz_default_plugins/Marker + Enabled: true + Name: Marker + Namespaces: + barrier: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /planning/barrier_marker Value: true Enabled: true Global Options: Background Color: 222; 255; 251 - Fixed Frame: base_link + Fixed Frame: hero Frame Rate: 30 Name: root Tools: @@ -466,31 +800,40 @@ Visualization Manager: Value: true Views: Current: - Angle: -1.5900014638900757 - Class: rviz_default_plugins/TopDownOrtho + Class: rviz_default_plugins/Orbit + Distance: 79.5810775756836 Enable Stereo Rendering: Stereo Eye Separation: 0.05999999865889549 Stereo Focal Distance: 1 Swap Stereo Eyes: false Value: false + Focal Point: + X: 0.930766761302948 + Y: -4.274430274963379 + Z: 1.7611576318740845 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 Invert Z Axis: false Name: Current View Near Clip Distance: 0.009999999776482582 - Scale: 2.3929734230041504 + Pitch: 1.3097965717315674 Target Frame: - Value: TopDownOrtho (rviz_default_plugins) - X: 106.26571655273438 - Y: -53.685054779052734 + Value: Orbit (rviz_default_plugins) + Yaw: 3.0673749446868896 Saved: ~ Window Geometry: Bird's Eye: collapsed: false + Camera: + collapsed: false Displays: collapsed: false - Height: 932 + Height: 956 Hide Left Dock: false - Hide Right Dock: false - QMainWindow State: 000000ff00000000fd0000000400000000000001560000028bfc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003b0000028b000000c700fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000057c0000082dfc0200000005fb0000001400430065006e0074006500720020005200470042000000019b000006fb0000000000000000fb0000001000530065006d0061006e00740069006300000001d9000001b00000000000000000fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000020100000188000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000005f6000000bdfc0100000008fb0000001a00530065006d0061006e0074006900630020004c0065006600740100000000000001360000008800fffffffb0000001c00530065006d0061006e007400690063002000520069006700680074010000013c000001390000009000fffffffc0000027b000001020000007200fffffffa000000010200000002fb0000001c00530065006d0061006e0074006900630020005200690067006800740000000000ffffffff0000000000000000fb0000001200520047004200200052006900670068007401000008a2000001f50000002800fffffffb000000100052004700420020004c0065006600740100000383000001340000006900fffffffb00000014004200690072006400270073002000450079006501000004bd000001390000007000fffffffb0000000a004400650070007400680000000000000007800000000000000000fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d006501000000000000045000000000000000000000049a0000028b00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Hide Right Dock: true + QMainWindow State: 000000ff00000000fd0000000400000000000001dc000001f3fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001c8000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afc0000003b000001f3000000c700fffffffa000000010100000002fb0000000c00430061006d0065007200610000000000ffffffff0000006400fffffffb000000100044006900730070006c0061007900730100000000000001560000015600fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000022c0000028afc0200000007fb0000000c00430061006d006500720061010000003b0000022f0000000000000000fb0000001400430065006e0074006500720020005200470042000000019b000006fb0000000000000000fb0000001000530065006d0061006e00740069006300000001d9000001b00000000000000000fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003b0000028a000000a000fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b20000000000000000fb0000001800460072006f006e0074002000430061006d0065007200610000000000ffffffff000000000000000000000002000003c0000000d9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007800000016dfc010000000efb0000001400420069007200640027007300200045007900650100000000000001f80000007000fffffffb000000100052004700420020004c00650066007401000001fe000001d00000006900fffffffb00000014005200470042002000430065006e00740065007201000003d4000001c90000007a00fffffffb0000001200520047004200200052006900670068007401000005a3000001dd0000007200fffffffb0000001a00530065006d0061006e0074006900630020004c0065006600740000000000000002780000008800fffffffb0000001c00530065006d0061006e00740069006300200052006900670068007400000001de000001dc0000009000fffffffb000000100052004700420020004c00650066007401000002d3000001dd0000000000000000fc000004b6000000ea0000000000fffffffa000000000200000002fb0000001c00530065006d0061006e0074006900630020005200690067006800740000000000ffffffff0000000000000000fb0000001200520047004200200052006900670068007401000008a2000001f50000000000000000fb00000014004200690072006400270073002000450079006500000004d1000001250000000000000000fb0000000a004400650070007400680000000000000007800000000000000000fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d00650100000000000004500000000000000000fb0000000a0049006d0061006700650000000000ffffffff0000000000000000fb0000000a0049006d0061006700650000000000ffffffff00000000000000000000059e000001f300000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + RGB Center: + collapsed: false RGB Left: collapsed: false RGB Right: @@ -504,7 +847,7 @@ Window Geometry: Tool Properties: collapsed: false Views: - collapsed: false - Width: 1526 - X: 74 + collapsed: true + Width: 1920 + X: 0 Y: 27 diff --git a/src/perception/ROSOccupancyGridPrediction/models/prednet.pt b/data/perception/models/prednet.pt similarity index 100% rename from src/perception/ROSOccupancyGridPrediction/models/prednet.pt rename to data/perception/models/prednet.pt diff --git a/src/perception/ROSOccupancyGridPrediction/models/prednet_with_saa.pt b/data/perception/models/prednet_with_saa.pt similarity index 100% rename from src/perception/ROSOccupancyGridPrediction/models/prednet_with_saa.pt rename to data/perception/models/prednet_with_saa.pt diff --git a/src/perception/ROSOccupancyGridPrediction/models/prednet_with_taa.pt b/data/perception/models/prednet_with_taa.pt similarity index 100% rename from src/perception/ROSOccupancyGridPrediction/models/prednet_with_taa.pt rename to data/perception/models/prednet_with_taa.pt diff --git a/data/routes_town02.xml b/data/routes_town02.xml new file mode 100644 index 000000000..e7f878803 --- /dev/null +++ b/data/routes_town02.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo.png b/demo.png deleted file mode 100644 index 1e82d7a07..000000000 Binary files a/demo.png and /dev/null differ diff --git a/docker.sh b/docker.sh index 462d53813..c0e9c3a47 100755 --- a/docker.sh +++ b/docker.sh @@ -2,22 +2,54 @@ # To build: 'docker build -t navigator .' -# Give the Docker container access to the x server, -# which allows it to show graphical applications -xhost + + # The below command is to run a docker container. The container must already be built. # It passes the ROS_DOMAIN_ID from host. To generate this "randomly" based on your username, # see https://gist.github.com/wheitman/ceaec50cd4cb79a496f43e6c0e20a8b2 + + +if echo $* | grep -e "-h" -q +then + echo "Usage: ./docker.sh" + echo "Add --no-gpu to skip GPUs" + exit +fi + +# Give the Docker container access to the x server, +# which allows it to show graphical applications +xhost + + +# Without GPUs +if echo $* | grep -e "--no-gpu" -q +then + echo "GPUS DISABLED" + docker run \ + -it \ + --rm \ + -v $PWD:/navigator \ + -v /home/share/carla:/workspace \ + -v /dev:/dev \ + --net=host \ + --privileged \ + -v $HOME/.Xauthority:/root/.Xauthority \ + -v /tmp/.X11-unix:/tmp/.X11-unix \ + -e="DISPLAY" \ + -e ROS_DOMAIN_ID \ + navigator +else # With GPUs docker run \ -it \ --rm \ - --gpus all \ -v $PWD:/navigator \ -v /home/share/carla:/workspace \ + -v /dev:/dev \ + --gpus all \ --net=host \ --privileged \ -v $HOME/.Xauthority:/root/.Xauthority \ + -v /tmp/.X11-unix:/tmp/.X11-unix \ -e="DISPLAY" \ -e ROS_DOMAIN_ID \ navigator +fi \ No newline at end of file diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index a59849ea4..fe15b3101 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -14,6 +14,8 @@ echo "🦊 Sourcing ROS2 Foxy..." source /opt/ros/foxy/setup.bash echo "🔗 Configuring the ROS DDS..." +FASTRTPS_DEFAULT_PROFILES_FILE=/navigator/data/fastrtps.xml +RMW_FASTRTPS_USE_QOS_FROM_XML=1 export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp source /opt/cyclone_ws/install/setup.bash diff --git a/docker/install-dependencies.sh b/docker/install-dependencies.sh index 956b3e809..6b6d226ce 100755 --- a/docker/install-dependencies.sh +++ b/docker/install-dependencies.sh @@ -3,17 +3,15 @@ apt-get update apt-get install -y ros-foxy-diagnostic-updater \ -ros-foxy-velodyne-msgs \ +libfprint-2-2:amd64 \ +libpam-fprintd:amd64 \ +fprintd + +apt install -y ros-foxy-velodyne-msgs \ ros-foxy-velodyne-driver \ ros-foxy-velodyne-laserscan \ -ros-foxy-velodyne-pointcloud \ -ros-foxy-lanelet2-core \ -ros-foxy-lanelet2-io \ -ros-foxy-lanelet2-projection \ -ros-foxy-lanelet2 \ ros-foxy-tf-transformations \ ros-foxy-ros-testing \ -ros-foxy-lgsvl-msgs \ ros-foxy-vision-opencv \ ros-foxy-pcl-conversions \ software-properties-common \ @@ -32,4 +30,5 @@ ros-foxy-rviz2 \ ros-foxy-robot-localization \ ros-foxy-derived-object-msgs \ byobu \ +ros-foxy-velodyne-pointcloud \ nvidia-cuda-toolkit \ No newline at end of file diff --git a/docker/install-pip-dependencies.sh b/docker/install-pip-dependencies.sh index 95ca3b14e..9ada835bc 100755 --- a/docker/install-pip-dependencies.sh +++ b/docker/install-pip-dependencies.sh @@ -23,7 +23,9 @@ ephem \ matplotlib \ six \ simple-watchdog-timer \ -numpy +numpy \ +python-can \ +pyserial # distro \ # torch==1.12.0 \ # torchvision \ diff --git a/docs/_config.yml b/docs/_config.yml index e0ab94ebf..ea2064a41 100755 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -48,6 +48,14 @@ nav_external_links: url: https://nova-utd.github.io hide_icon: false # set to true to hide the external link icon - defaults to false +callouts: + warning: + title: Warning + color: red + example: + title: Example + color: green + # Exclude from processing. # The following items will not be processed, by default. # Any item listed under the `exclude:` key here will be automatically added to diff --git a/docs/_sass/color_schemes/novalicious.scss b/docs/_sass/color_schemes/novalicious.scss index 7f89363bb..edef9f2c3 100755 --- a/docs/_sass/color_schemes/novalicious.scss +++ b/docs/_sass/color_schemes/novalicious.scss @@ -1,3 +1,83 @@ $link-color: #F08700; $body-font-family: "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; -$btn-primary-color: #F08700; \ No newline at end of file +$btn-primary-color: #F08700; + +.swatch { + padding: 0.5rem; + vertical-align: middle; + display: inline-block; + box-sizing: border-box; + margin-right: 0.25rem; +} + +.bg-road { + background-color: rgb(128, 64, 128); +} + +.bg-building { + background-color: rgb(70, 70, 70); +} + +.bg-sidewalk { + background-color: rgb(244, 35, 232); +} + +.bg-person { + background-color: rgb(220, 20, 60); +} + +.bg-car { + background-color: rgb(0, 0, 142); +} + + + +.bg-fence{ + background-color: rgb(100, 40, 40); +} +.bg-pole{ + background-color: rgb(153, 153, 153); +} +.bg-traffic-sign { + background-color: rgb(220, 220, 0); +} +.bg-traffic-light { + background-color: rgb(250, 170, 30); +} +.bg-vegetation { + background-color: rgb(107, 142, 35); +} +.bg-terrain { + background-color: rgb(145, 170, 100); +} +.bg-sky { + background-color: rgb(70, 130, 180); +} + +.bg-wall { + background-color: rgb(102,102,156); +} + +.bg-rider { + background-color: rgb(255,0,0); +} + +.bg-truck { + background-color: rgb( 0, 0, 70); +} + +.bg-bus { + background-color: rgb( 0, 60,100) +} + +.bg-train { + background-color: rgb( 0, 80,100) +} + +.bg-motorcycle { + background-color: rgb( 0, 0,230); +} + +.bg-bicycle { + background-color: rgb(119, 11, 32); +} diff --git a/docs/_site/404.html b/docs/_site/404.html index 517162145..2b5a4822c 100755 --- a/docs/_site/404.html +++ b/docs/_site/404.html @@ -1 +1 @@ - Navigator | Navigator is an open-source autonomous driving system developed by Nova, an applied research group at UT Dallas. Skip to main content Link Menu Expand (external link) Document Search Copy Copied

404

Page not found :(

The requested page could not be found.

+ Navigator | Navigator is an open-source autonomous driving system developed by Nova, an applied research group at UT Dallas. Skip to main content Link Menu Expand (external link) Document Search Copy Copied

404

Page not found :(

The requested page could not be found.

diff --git a/docs/_site/assets/css/just-the-docs-dark.css b/docs/_site/assets/css/just-the-docs-dark.css index c9d6e9c32..310c952a7 100755 --- a/docs/_site/assets/css/just-the-docs-dark.css +++ b/docs/_site/assets/css/just-the-docs-dark.css @@ -725,6 +725,10 @@ figure.highlight pre, figure.highlight :not(pre) > code { overflow-x: auto; padd code.language-mermaid { padding: 0; background-color: inherit; border: 0; } +.highlight, pre.highlight { background: #31343f; color: #dee2f7; } + +.highlight pre { background: #31343f; } + .text-grey-dk-000 { color: #959396 !important; } .text-grey-dk-100 { color: #5c5962 !important; } @@ -2396,3 +2400,33 @@ a.skip-to-main { left: -999px; position: absolute; top: auto; width: 1px; height a.skip-to-main:focus, a.skip-to-main:active { color: #2c84fa; background-color: #27262b; left: auto; top: auto; width: 30%; height: auto; overflow: auto; margin: 10px 35%; padding: 5px; border-radius: 15px; border: 4px solid #264caf; text-align: center; font-size: 1.2em; z-index: 999; } div.opaque { background-color: #27262b; } + +p.warning, blockquote.warning { background: rgba(221, 46, 46, 0.2); border-left: 4px solid #f77e7e; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.warning::before, blockquote.warning::before { color: #f77e7e; content: "Warning"; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } +p.warning > .warning-title, blockquote.warning > .warning-title { color: #f77e7e; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +p.warning-title, blockquote.warning-title { background: rgba(221, 46, 46, 0.2); border-left: 4px solid #f77e7e; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.warning-title > p:first-child, blockquote.warning-title > p:first-child { margin-top: 0; margin-bottom: 0; color: #f77e7e; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +blockquote.warning { margin-left: 0; margin-right: 0; } +blockquote.warning > p:first-child { margin-top: 0; } +blockquote.warning > p:last-child { margin-bottom: 0; } + +blockquote.warning-title { margin-left: 0; margin-right: 0; } +blockquote.warning-title > p:nth-child(2) { margin-top: 0; } +blockquote.warning-title > p:last-child { margin-bottom: 0; } + +p.example, blockquote.example { background: rgba(2, 110, 87, 0.2); border-left: 4px solid #41d693; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.example::before, blockquote.example::before { color: #41d693; content: "Example"; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } +p.example > .example-title, blockquote.example > .example-title { color: #41d693; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +p.example-title, blockquote.example-title { background: rgba(2, 110, 87, 0.2); border-left: 4px solid #41d693; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.example-title > p:first-child, blockquote.example-title > p:first-child { margin-top: 0; margin-bottom: 0; color: #41d693; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +blockquote.example { margin-left: 0; margin-right: 0; } +blockquote.example > p:first-child { margin-top: 0; } +blockquote.example > p:last-child { margin-bottom: 0; } + +blockquote.example-title { margin-left: 0; margin-right: 0; } +blockquote.example-title > p:nth-child(2) { margin-top: 0; } +blockquote.example-title > p:last-child { margin-bottom: 0; } diff --git a/docs/_site/assets/css/just-the-docs-default.css b/docs/_site/assets/css/just-the-docs-default.css index 500357b5d..8c6c195d4 100755 --- a/docs/_site/assets/css/just-the-docs-default.css +++ b/docs/_site/assets/css/just-the-docs-default.css @@ -135,6 +135,46 @@ .highlight .il { color: #2aa198; } +.swatch { padding: 0.5rem; vertical-align: middle; display: inline-block; box-sizing: border-box; margin-right: 0.25rem; } + +.bg-road { background-color: #804080; } + +.bg-building { background-color: #464646; } + +.bg-sidewalk { background-color: #f423e8; } + +.bg-person { background-color: crimson; } + +.bg-car { background-color: #00008e; } + +.bg-fence { background-color: #642828; } + +.bg-pole { background-color: #999999; } + +.bg-traffic-sign { background-color: #dcdc00; } + +.bg-traffic-light { background-color: #faaa1e; } + +.bg-vegetation { background-color: olivedrab; } + +.bg-terrain { background-color: #91aa64; } + +.bg-sky { background-color: steelblue; } + +.bg-wall { background-color: #66669c; } + +.bg-rider { background-color: red; } + +.bg-truck { background-color: #000046; } + +.bg-bus { background-color: #003c64; } + +.bg-train { background-color: #005064; } + +.bg-motorcycle { background-color: #0000e6; } + +.bg-bicycle { background-color: #770b20; } + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document ========================================================================== */ /** 1. Correct the line height in all browsers. 2. Prevent adjustments of font size after orientation changes in iOS. */ @@ -597,6 +637,10 @@ figure.highlight pre, figure.highlight :not(pre) > code { overflow-x: auto; padd code.language-mermaid { padding: 0; background-color: inherit; border: 0; } +.highlight, pre.highlight { background: #f5f6fa; color: #5c5962; } + +.highlight pre { background: #f5f6fa; } + .text-grey-dk-000 { color: #959396 !important; } .text-grey-dk-100 { color: #5c5962 !important; } @@ -2268,3 +2312,33 @@ a.skip-to-main { left: -999px; position: absolute; top: auto; width: 1px; height a.skip-to-main:focus, a.skip-to-main:active { color: #F08700; background-color: #fff; left: auto; top: auto; width: 30%; height: auto; overflow: auto; margin: 10px 35%; padding: 5px; border-radius: 15px; border: 4px solid #F08700; text-align: center; font-size: 1.2em; z-index: 999; } div.opaque { background-color: #fff; } + +p.warning, blockquote.warning { background: rgba(247, 126, 126, 0.2); border-left: 4px solid #dd2e2e; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.warning::before, blockquote.warning::before { color: #dd2e2e; content: "Warning"; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } +p.warning > .warning-title, blockquote.warning > .warning-title { color: #dd2e2e; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +p.warning-title, blockquote.warning-title { background: rgba(247, 126, 126, 0.2); border-left: 4px solid #dd2e2e; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.warning-title > p:first-child, blockquote.warning-title > p:first-child { margin-top: 0; margin-bottom: 0; color: #dd2e2e; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +blockquote.warning { margin-left: 0; margin-right: 0; } +blockquote.warning > p:first-child { margin-top: 0; } +blockquote.warning > p:last-child { margin-bottom: 0; } + +blockquote.warning-title { margin-left: 0; margin-right: 0; } +blockquote.warning-title > p:nth-child(2) { margin-top: 0; } +blockquote.warning-title > p:last-child { margin-bottom: 0; } + +p.example, blockquote.example { background: rgba(65, 214, 147, 0.2); border-left: 4px solid #026e57; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.example::before, blockquote.example::before { color: #026e57; content: "Example"; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } +p.example > .example-title, blockquote.example > .example-title { color: #026e57; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +p.example-title, blockquote.example-title { background: rgba(65, 214, 147, 0.2); border-left: 4px solid #026e57; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.example-title > p:first-child, blockquote.example-title > p:first-child { margin-top: 0; margin-bottom: 0; color: #026e57; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +blockquote.example { margin-left: 0; margin-right: 0; } +blockquote.example > p:first-child { margin-top: 0; } +blockquote.example > p:last-child { margin-bottom: 0; } + +blockquote.example-title { margin-left: 0; margin-right: 0; } +blockquote.example-title > p:nth-child(2) { margin-top: 0; } +blockquote.example-title > p:last-child { margin-bottom: 0; } diff --git a/docs/_site/assets/css/just-the-docs-light.css b/docs/_site/assets/css/just-the-docs-light.css index 2338f3b92..571bd374b 100755 --- a/docs/_site/assets/css/just-the-docs-light.css +++ b/docs/_site/assets/css/just-the-docs-light.css @@ -733,6 +733,10 @@ figure.highlight pre, figure.highlight :not(pre) > code { overflow-x: auto; padd code.language-mermaid { padding: 0; background-color: inherit; border: 0; } +.highlight, pre.highlight { background: #f5f6fa; color: #5c5962; } + +.highlight pre { background: #f5f6fa; } + .text-grey-dk-000 { color: #959396 !important; } .text-grey-dk-100 { color: #5c5962 !important; } @@ -2404,3 +2408,33 @@ a.skip-to-main { left: -999px; position: absolute; top: auto; width: 1px; height a.skip-to-main:focus, a.skip-to-main:active { color: #7253ed; background-color: #fff; left: auto; top: auto; width: 30%; height: auto; overflow: auto; margin: 10px 35%; padding: 5px; border-radius: 15px; border: 4px solid #5e41d0; text-align: center; font-size: 1.2em; z-index: 999; } div.opaque { background-color: #fff; } + +p.warning, blockquote.warning { background: rgba(247, 126, 126, 0.2); border-left: 4px solid #dd2e2e; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.warning::before, blockquote.warning::before { color: #dd2e2e; content: "Warning"; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } +p.warning > .warning-title, blockquote.warning > .warning-title { color: #dd2e2e; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +p.warning-title, blockquote.warning-title { background: rgba(247, 126, 126, 0.2); border-left: 4px solid #dd2e2e; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.warning-title > p:first-child, blockquote.warning-title > p:first-child { margin-top: 0; margin-bottom: 0; color: #dd2e2e; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +blockquote.warning { margin-left: 0; margin-right: 0; } +blockquote.warning > p:first-child { margin-top: 0; } +blockquote.warning > p:last-child { margin-bottom: 0; } + +blockquote.warning-title { margin-left: 0; margin-right: 0; } +blockquote.warning-title > p:nth-child(2) { margin-top: 0; } +blockquote.warning-title > p:last-child { margin-bottom: 0; } + +p.example, blockquote.example { background: rgba(65, 214, 147, 0.2); border-left: 4px solid #026e57; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.example::before, blockquote.example::before { color: #026e57; content: "Example"; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } +p.example > .example-title, blockquote.example > .example-title { color: #026e57; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +p.example-title, blockquote.example-title { background: rgba(65, 214, 147, 0.2); border-left: 4px solid #026e57; border-radius: 4px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08); padding: .8rem; } +p.example-title > p:first-child, blockquote.example-title > p:first-child { margin-top: 0; margin-bottom: 0; color: #026e57; display: block; font-weight: bold; text-transform: uppercase; font-size: .75em; padding-bottom: .125rem; } + +blockquote.example { margin-left: 0; margin-right: 0; } +blockquote.example > p:first-child { margin-top: 0; } +blockquote.example > p:last-child { margin-bottom: 0; } + +blockquote.example-title { margin-left: 0; margin-right: 0; } +blockquote.example-title > p:nth-child(2) { margin-top: 0; } +blockquote.example-title > p:last-child { margin-bottom: 0; } diff --git a/docs/_site/assets/js/just-the-docs.js b/docs/_site/assets/js/just-the-docs.js index e7a7bacf5..552661d1c 100755 --- a/docs/_site/assets/js/just-the-docs.js +++ b/docs/_site/assets/js/just-the-docs.js @@ -475,7 +475,7 @@ jtd.onReady(function(){ copyButton.addEventListener('click', function () { if(timeout === null) { - var code = codeBlock.querySelector('pre:not(.lineno)').innerText; + var code = (codeBlock.querySelector('pre:not(.lineno, .highlight)') || codeBlock.querySelector('code')).innerText; window.navigator.clipboard.writeText(code); copyButton.innerHTML = svgCopied; diff --git a/docs/_site/assets/js/search-data.json b/docs/_site/assets/js/search-data.json index 30d5296d6..cdfaadf51 100755 --- a/docs/_site/assets/js/search-data.json +++ b/docs/_site/assets/js/search-data.json @@ -1,564 +1,662 @@ {"0": { + "doc": "Airbags", + "title": "Airbags", + "content": "Maintained by Will Heitman . “Airbags” are what we call safety zones that limit our vehicle’s speed. Airbags form a low-level safety system that is one step above a similar automatic emergency braking (AEB) system. The logic is simple. We establish three safety zones (red, amber, and yellow), where our speed is limited to varying degrees. If any region within these zones is occupied by a LiDAR point, the vehicle’s speed will be limited to the zone’s value. If no LiDAR point falls within the zone, the speed is not limited. In the case of a speed limitation, if the car is currently traveling faster than the zone allows, the airbag system will send a 100% brake command. Airbags extend in front of the vehicle, and slightly to either side. Above: Diagram of airbag dimensions . ", + "url": "/navigator/planning/airbags.html", + + "relUrl": "/planning/airbags.html" + },"1": { "doc": "Contributing", "title": "Contributing overview", "content": "Maintained by Raghav Pillai . ", "url": "/navigator/contributing/contributing-overview.html#contributing-overview", "relUrl": "/contributing/contributing-overview.html#contributing-overview" - },"1": { + },"2": { "doc": "Contributing", "title": "Table of contents", "content": ". | Source Control & Git . | Branching & Feature Branches | . | Documentation . | Headers | Function & Inline Documentation . | Examples: | C++ | Python | C++ | Python | . | . | READMEs | Code Standards and Guidelines | Styling | Variable initialization | Abstraction | Types, typing and type hinting | Constants and parameters | Misc | . As an open source project, Navigator is always evolving and improving. We open our arms to anyone who’d like to contribute. To help guide contributors, we’ve developed detailed Code Guidelines & Standards, as well as documentation and branching guidelines that allow us to have a consistent developer experience regardless of author. This revolves around three main philosophies: . | Inherent Readability | Consistency | Maintainability | . By following these guidelines, we can fulfill these philosophies, which allow us to have the most efficient developer experience possible, along with having a mature and maintainable codebase. ", "url": "/navigator/contributing/contributing-overview.html#table-of-contents", "relUrl": "/contributing/contributing-overview.html#table-of-contents" - },"2": { + },"3": { "doc": "Contributing", "title": "Source Control & Git", "content": ". | Use the branching strategy described below. Do not commit directly to the main or dev branch. This applies even to simple changes, like fixing a typo! | Don’t merge your own pull requests to main, dev or release branches. Get the software architect or team lead to review your change and merge it. | Commit as often or as infrequently as you like. As long as you’re working in a branch (as described below), you can commit even a completely broken change without affecting others. | . Branching & Feature Branches . We will maintain both a main branch and a dev branch. main is more stable than dev. When you begin work on a feature or a bugfix, fork the dev branch, implement your change, and create a pull request back to dev once the change is relatively stable and well tested. Start branch names with ‘feature_’, but other than that, name them however you want. Make the name descriptive and helpful. Don’t name a branch feature_zcc - that name is not helpful to someone trying to understand what the branch is for. However, feature_zed_camera_color clearly describes what the branch is for. Make sure your commits are meaningful and grouped up. Don’t commit your entire change history into a single commit, group them up so you have a timeline of your progress. When we are preparing for a release, we will create a branch off of dev to test and and add bugfixes. This release will start with release_ and end with a version number - for example, release_1_0. This allows us to continue merging features into dev while a release is being worked on. Once testing is complete, the release branch will be merged into both main and dev, so that the fixes applied during testing are applied everywhere. The commit in main will be tagged as our new release. ", "url": "/navigator/contributing/contributing-overview.html#source-control--git", "relUrl": "/contributing/contributing-overview.html#source-control--git" - },"3": { + },"4": { "doc": "Contributing", "title": "Documentation", "content": "A cornerstone of good code is maintainability, which relies on understandable documentation. Navigator uses Doxygen to automatically generate high-level documentation from our user-defined documentation. Further documentation on how this works can be found below: . https://doxygen.nl/manual/docblocks.html . You can also use the VSCode Doxygen Generator to automatically generate proper documentation templates. Below are the different types of documentation that are required for new contributions for Navigator. Headers . Each file should have documentation on what the file accomplishes, as well as basic usage information. Below is our sample header comment template. /* * Package: package_name * Filename: FileName.cpp * Author: John Doe * Email: john.doe@example.com (Use either school or personal) * Copyright: 2021, Nova UTD * License: MIT License Description of what this file does, what inputs it takes and what it outputs or accomplishes */ . Function & Inline Documentation . Each function should have a Docblock, which documents a specific segment of code (in this case, a Function). Navigator is mainly built on C++ and Python, so below will be examples of Docblocks for each. Note that documentation MUST appear before the declaration it describes, and with the same indentation. These concepts revolve around three main components: . | Description: Description of what the function does | @param: Input type, name and description that’s taken into the function | @return: Return type and description that’s returned from the function | . A good resource for documentation is below. https://developer.lsst.io/cpp/api-docs.html . Examples: . C++ . /** * Sum numbers in a vector. * * @param values[vector<double>] Container whose values are summed. * @return double sum of `values`, or 0.0 if `values` is empty. */ double sum(std::vector<double> & const values) { ... } . Python . def map_range(number: int, in_min: int, in_max: int, out_min: int, out_max: int) -> int: \"\"\"! Maps a number from one range to another. @param number[int] The input number to map. @param in_min[int] The minimum value of an input number. @param in_max[int] The maximum value of an input number. @param out_min[int] The minimum value of an output number. @param out_max[int] The maximum value of an output number. @return int Mapped number. \"\"\" ... In cases with no parameters or return (ex: constructors, abstracted functions), you can use the below Docblock . C++ . /** * Sum numbers in a vector. */ void main() { ... } . Python . def init(): \"\"\"! Initializes the program.\"\"\" . ", "url": "/navigator/contributing/contributing-overview.html#documentation", "relUrl": "/contributing/contributing-overview.html#documentation" - },"4": { + },"5": { "doc": "Contributing", "title": "READMEs", "content": "Each subsystem and package must have a README explaining what the directory accomplishes. An example of how these READMEs should be distributed are below. navigator/ - .. - README.md - src/ - .. - README.md - planning/ - .. - README.md - motion_planner/ - .. - README.md . ", "url": "/navigator/contributing/contributing-overview.html#readmes", "relUrl": "/contributing/contributing-overview.html#readmes" - },"5": { + },"6": { "doc": "Contributing", "title": "Code Standards and Guidelines", "content": "Code standards and guidelines are a set of rules and best practices that help us create cleaner, readable and more maintainable code with minimal errors. This help us keep a cleaner, more consistent codebase. This helps us guarantee better code quality, lower code complexity and make more meaningful contributions over time. This all comes down to having better maintainability over time as we scale up our project. Prefer readability over performance in most code. The obvious exception to this is code that is going to process a large amount of data (ie, the inner loop of a downsampler). However, much of our code runs relatively infrequently, so small performance gains are not worth obfuscating our code. ", "url": "/navigator/contributing/contributing-overview.html#code-standards-and-guidelines", "relUrl": "/contributing/contributing-overview.html#code-standards-and-guidelines" - },"6": { + },"7": { "doc": "Contributing", "title": "Styling", "content": "As our stack mainly contains C++ and Python code, we chose two styling guidelines for such, these being Google’s C++ guidelines for C++, and PEP 8 for Python. We heavily recommend you read at least an overview of these two guidelines. The main takeways for such are below: . | Classes/class names should be in PascalCase | The names of variables (including function parameters) and data members are all lowercase, with underscores between words (snake_case) (eg: our_variable) | Constants should be fully uppercase (eg: OUR_CONSTANT) | Bracket initialization should be done on the same line as initialization | Indentation should be performed with a singular tab, equivalent to four spaces | Data members of classes (but not structs) additionally have trailing underscores. (eg: a_local_variable, a_struct_data_member,a_class_data_member_) | Filenames should be all lowercase and can include underscores (_) | Place a function’s variables in the narrowest scope possible, and initialize variables in the declaration | . ", "url": "/navigator/contributing/contributing-overview.html#styling", "relUrl": "/contributing/contributing-overview.html#styling" - },"7": { + },"8": { "doc": "Contributing", "title": "Variable initialization", "content": "Variables should be named in snake_case, and should be as verbose as possible. This allows for inherent readability. Examples of this are as below: . | boolean functions and variables should be something like is_item_exists | integer functions and variables should be something like num_items | . Names should be meaningful, even if it makes them very long. Good names are the #1 factor in writing readable code! Do NOT write int inchs = read(sa, b, BUFSZ); - instead write int characters_read = read(socket, buffer, buffer_size) . ", "url": "/navigator/contributing/contributing-overview.html#variable-initialization", "relUrl": "/contributing/contributing-overview.html#variable-initialization" - },"8": { + },"9": { "doc": "Contributing", "title": "Abstraction", "content": "Abstract as much as possible! This helps with general code cleanliness and readability. | Split up as much as possible into different functions, we want to reuse as much code as possible | Split common code into libraries, and have libraries on the highest level of use (eg. code across subsystems should be put into that level of directory, code across packages should be put into that level of directory) | Don’t reinvent the wheel! If you can use existing code rather than writing your own, you usually should. This saves time and often results in using more mature code than we could write ourselves. | If you end up writing a general-purpose utility of some sort, write it in its own package so that other packages can require it later on (see voltron_test_utils for an example) | If you need to work with low-level OS functionality (eg, CAN interfaces), either isolate this part of the code in a safe, RAII (Resource Acquisition Is Initilization - look this up if you’re unfamiliar with it), C++-style class, or use a library that provides this same functionality. Don’t scatter the magic system calls, manual memory management, etc throughout your code. | . Live by the DRY philisophy - Don’t Repeat Yourself (“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system”). This means reducing repetition of patterns and code duplication, and avoiding code redundancy and duplication. ", "url": "/navigator/contributing/contributing-overview.html#abstraction", "relUrl": "/contributing/contributing-overview.html#abstraction" - },"9": { + },"10": { "doc": "Contributing", "title": "Types, typing and type hinting", "content": "Especially in Python, we want to make sure we use specific types. This helps us catch more error while building instead of during runtime, makes it easier to understand what a piece of code does through inherant code readability, and makes it easier for us to maintain! For example, we don’t want to use auto in C++, as this makes it difficult to infer what the variable actually does, instead specifically define the type. An example in Python of typing and type hinting can be found below. def func(foo: int, bar: str) -> List: ques: str = str(foo) return [ques,bar] . ", "url": "/navigator/contributing/contributing-overview.html#types-typing-and-type-hinting", "relUrl": "/contributing/contributing-overview.html#types-typing-and-type-hinting" - },"10": { + },"11": { "doc": "Contributing", "title": "Constants and parameters", "content": "All constants and parameters should be moved out of the file, or on the top of files. This allows us to define constants at the highest possible level, and allow better readability. If constants require redefining at any point, they’ll need to be moved into the root param.yaml file. If not, put them at the top of the file, styled in accordance to our styling guidelines. ", "url": "/navigator/contributing/contributing-overview.html#constants-and-parameters", "relUrl": "/contributing/contributing-overview.html#constants-and-parameters" - },"11": { + },"12": { "doc": "Contributing", "title": "Misc", "content": ". | Everything should be nested under the navigator::package_name namespace | C++ source files should use a .cpp extension. Header files should use a .hpp extension | . ", "url": "/navigator/contributing/contributing-overview.html#misc", "relUrl": "/contributing/contributing-overview.html#misc" - },"12": { + },"13": { "doc": "Contributing", "title": "Contributing", "content": " ", "url": "/navigator/contributing/contributing-overview.html", "relUrl": "/contributing/contributing-overview.html" - },"13": { + },"14": { "doc": "Controls", "title": "Controls overview", "content": "Maintained by Egan Johnson . ", "url": "/navigator/controls/controls-overview.html#controls-overview", "relUrl": "/controls/controls-overview.html#controls-overview" - },"14": { + },"15": { "doc": "Controls", "title": "Table of contents", "content": ". | Sources of error | Current controllers | . The Controls system takes our vehicle’s current state and our target trajectory as inputs. Based on the difference between our current state and this desired trajectory, the system calculates the ideal: . | Steering angle | Brake position | Throttle position | . To make our system platform-agnostic, the Controller’s outputs are between (-1.0, 1.0) for steering and (0.0, 1.0) for throttle and brake positions. The Interface system is responsible for scaling these values to a specific platform. ", "url": "/navigator/controls/controls-overview.html#table-of-contents", "relUrl": "/controls/controls-overview.html#table-of-contents" - },"15": { + },"16": { "doc": "Controls", "title": "Sources of error", "content": "The vehicle does not move perfectly. Physical error is introduced. There will always be errors in our model– that is, our set of assumptions about the vehicle’s physical properties and behavior. Most importantly, there’s error in our current state, one of the inputs to our controller. In order for our controller to follow the desired trajectory, it must have an accurate understanding of where the car currently is, how fast it’s going, and which way it’s facing. ", "url": "/navigator/controls/controls-overview.html#sources-of-error", "relUrl": "/controls/controls-overview.html#sources-of-error" - },"16": { + },"17": { "doc": "Controls", "title": "Current controllers", "content": "Our “unified controller” generates the desired steering angle and pedal positions within the same node. However, steering and pedal positions are calculated using two different controllers. As of Sept. 21, 2022, our steering controller uses Pure Pursuit, while our throttle and brake are calculated using a simple PID controller. This combination works suitably at low speeds, though something more sophisticated like MPC would be necissary for highway driving. ", "url": "/navigator/controls/controls-overview.html#current-controllers", "relUrl": "/controls/controls-overview.html#current-controllers" - },"17": { + },"18": { "doc": "Controls", "title": "Controls", "content": " ", "url": "/navigator/controls/controls-overview.html", "relUrl": "/controls/controls-overview.html" - },"18": { + },"19": { "doc": "Behavior Planning and Controls Design Document (draft)", "title": "Behavior Planning and Controls Design Document (draft)", "content": "Maintained by Hansika . ", "url": "/navigator/planning/design.html", "relUrl": "/planning/design.html" - },"19": { + },"20": { "doc": "Behavior Planning and Controls Design Document (draft)", "title": "Table of contents", "content": ". | Important Definitions Used in Doc: | System overview . | Current system: . | Planning: | Controls: | . | What Planning intends to accomplish: | What Planning needs: . | Input: | Justification: | Proposed Planning System: | . | . | Proposed structure . | Current-State Information Required: | Representation of Surrounding Environment: | Dynamic Occupancy Grid: . | Structure of Grid: | Information within cell: | . | Conversion to Cost Map: . | Determination of Cost: | Distance From End: | Number of merges/turns: . | Good traffic navigation protocols: | . | Calculation of Path Costs: | . | . | . ", "url": "/navigator/planning/design.html#table-of-contents", "relUrl": "/planning/design.html#table-of-contents" - },"20": { + },"21": { "doc": "Behavior Planning and Controls Design Document (draft)", "title": "Important Definitions Used in Doc:", "content": "Configuration Space: set of all configurations of a vehicle . ", "url": "/navigator/planning/design.html#important-definitions-used-in-doc", "relUrl": "/planning/design.html#important-definitions-used-in-doc" - },"21": { + },"22": { "doc": "Behavior Planning and Controls Design Document (draft)", "title": "System overview", "content": "Current system: . Planning: . We use zones to determine speed at given way points, acting like an ‘on-rails’ vehicle. Zones are an enclosed region of space (represented as a polygon) with a maximum speed, which may be 0 to indicate a no-entry zone. Zones may overlap (in which case the lower speed wins). Zones may come from a variety of sources but currently originate from the Behavior Planner (Traffic Planner) and the Obstacle Zoner. Zones are currently not tagged with a type or origin: all zones are anonymous and equal. Controls: . Uses pure pursuit for steering control. The velocity controller is best not mentioned and should be replaced. What Planning intends to accomplish: . Develop a planning system that can take in a prediction about where cars, pedestrians, and other dynamic agents will be several seconds in the future and how we can find the most efficient trajectory for our autonomous vehicle (hereinafter referred to as the AV) on a short-term distance to get from point A to B (< a hundred feet) on a long-term path determined by widely spaced waypoints (> several miles). What Planning needs: . Input: . We choose to represent our prediction of the ground-truth state environment surrounding the AV several seconds in advanced using a Dynamic Occupancy Grid. This Dynamic Occupancy Grid will ideally hold information (in the form of probabilities) about whether a given grid cell (xn, yn) in a 2-Dimensional representation of real space (x, y) is occupied by an obstacle at some time tick t. This Dynamic Occupancy Grid will contain an individual grid frame (hereinafter referred to as a frame) for every discrete decisecond time tick for up to 3 seconds in advance of the current time state t = 0. Each of the frames in the Dynamic Occupancy Grid will be based on the local coordinate grid system around the AV. Justification: . Because safety is the highest priority when designing a AV planning system, our primary goal is to ensure that crashes never occur when our vehicle has the ability to avoid them. For simplicity, we treat all crashes with equal importance, meaning crashing with an animal, pedestrian, or other vehicles are all given equal “badness”. Defining a crash as the collision between the bounding boxes of two objects within real space, the only information we need to know is when another object’s bounding box will collide with our own. Knowing this, we can track all possible collisions with other dynamic and static objects through creating a Dynamic Occupancy Grid that tells us the spaces that contain other objects at some time t, for which we should not also occupy at that time t. The usefulness of the Dynamic Occupancy Grid is that all agents within our environment can be easily represented under the Grid because they all can be easily and efficiently sampled for any (x, y, t), whereas Zones struggled with efficiency and was unable to represent time altogether. Proposed Planning System: . Our proposed behavior planning and controls subsystem takes in a dynamic Occupancy Grid as the input for our planning system. Our planning system will output a path of waypoints finely spaced by equal time steps to help navigate the car to the correct location. In order to make this possible, we have outlined some approaches/options for planning and controls. This document outlines our proposed methods and how they fit together to form a cohesive subsystem. It describes what our system is not responsible for as well. Finally, it compares our proposed methods to Navigator’s current approach and to other popular methods in the literature. ", "url": "/navigator/planning/design.html#system-overview", "relUrl": "/planning/design.html#system-overview" - },"22": { + },"23": { "doc": "Behavior Planning and Controls Design Document (draft)", "title": "Proposed structure", "content": ". Current-State Information Required: . Position (x,y,z) Linear velocities (vx, vy, vz) . Orientation (Theta_x, Theya_y, Theta_z) angular velocities (wx, wy, wz) (Egan: take a brief look into use of quaternions for modeling orientation and its derivatives, as that’s what currently is used) . Short-term local coordinate transform history . Representation of Surrounding Environment: . Source: [1] . Voroni Diagrams: unsuitable for non-holonomic vehicles (cars) . State lattices: repeating primitive paths which connect possible states for the vehicle [1] . Dynamic Occupancy Grid: . Structure of Grid: . Each frame of the grid will be created around the local coordinate grid of the AV. It will span 40 meters to the left, 40 meters to the right, 40 meters behind, and 80 meters in front of the current position of the AV at time t = 0. Each grid cell will be made of squares spanning 0.2 meters long and wide. Each frame will represent a discrete time t = a/10 where a = (0, 30) such that our dynamic grid includes predictions from times t = (0, 3). The grid must be timestamped with when it was created so coordinate systems can be properly matched. The map is accessed via M[t, x,y], where higher values of x and y are to the front and right of the vehicle respectively. (The rear leftmost point is index (0,0)). Information within cell: . Each cell is associated with a probability of cell being occupied by an obstacle (float value). This probability will be in the range [0, 1]. Conversion to Cost Map: . Determination of Cost: . The primary factor associated with cost will be crashes. Trajectories that lead to crashes will be given extremely high costs to deter the planner from choosing them. The Dynamic Occupancy Grid can be converted into a Cost Map. Other factors to associate with cost are: Travel distance, number of merges/turns, good traffic navigation protocols, etc. We would also use the measure of traffic in different lanes to help us determine cost of a given path. Distance From End: . Each path should be assigned a cost value proportional to the maximum distance from its final position of the AV and the next waypoint. (Egan: I’m confused about this one. The point is that we maximize travel distance in the direction we want to go, and costs are relative to other paths, so consant cost increase don’t matter.) (Response – Chitsein: I think I was thinking incorrectly about travel distance’s relevance to the cost map – I meant for it to originally represent the travel distance between two points a and b. I realize that the RRT won’t be creating paths to get from a point a to b, but will rather find all paths that could be taken by the AV, so I think making Travel Distance represent a cost proportional to the maximum distance like you suggested would be the better design. ) . Number of merges/turns: . Increasing the cost of a path every time the AV merges or makes a turn to deter from paths that make unneccessary merges or turns. For example, we probably don’t want the vehicle to be merging in and out of lanes constantly on the highway to move a little faster at the expense of slowing down others cars it merges in front of and possibly increasing risk of collision. Good traffic navigation protocols: . Increase the cost of a path that do not follow good traffic navigation protocols. For example, imagine there is a line up of cars to turn right into the highway. Based on the cost map before good traffic navigation protocols are applied, the car could choose to turn into the left lane and then try to merge at the front of the line because it would decrease the time taken to get onto the highway. However, this would go against courteous driving practices, so we should teach the AV to wait it’s turn in the line. Calculation of Path Costs: . Each path’s cost is calculated based on the summation of the costs of each grid cell at time t (C[t, x, y]) plus the other factors associated with cost, including distance from end, number of merges/turns, and good traffic navigation protocols. Cost for travel from a given to another: Source [4] . We can represent the points into a graph with vertices being possible options given current position and environment. Edges are the transition from a given point (where AV currently is) to next point. We weight transition to be the following equation: Source [4] . Proposal (Egan, I think this makes sense, I also think that we may need to tweak this conversion when we try to decide algorithms that work best for RRTs - Hansika): We may additionally want a cost function more general than a summation over occupied cells. The specific case I’m thinking of is we want to encode that, where possible, the vehicle should end in drivable area at the prediction horizon- we don’t want to attempt to overtake where since it looks good now, but when the horizon rolls forward the vehicle realizes it was impossible halfway through. This cannot be encoded by a cost map alone. So a more general approach is: C(P)=∑C_i (P), where Pis the path under consideration, C(P) is the associated cost, and C_i (P) is a component cost function. So grid cost C_g (P)=∑8t▒∑{x \\〖in X〗t }▒∑{y∈Y_t }▒〖C[t,x,y]〗 . Tweaks based on the 10/13 meeting: We have two places to inject cost, which is the RRT cost function evaluated on a per-node basis and a function of the leaf nodes. • RRT cost: cost that can be evaluated at each node without knowing where it will end up ○ Cost map: occupancy grid, road semantics (drivable area) ○ Safety/Dynamic considerations: physical obtainability, difference between trajectory speed and road speed limit. A function of the state more than a lookup in the cost map. • Leaf nodes: ○ Whether the trajectory ends up in drivable area ○ Whether the trajectory ends up closer to the goal? This may be possible to push into RRT cost but makes more sense based on endpoints. RRTs: . Approach 1: Algorithm for RRTs with random sampling: [1] Input requirements: Configuration Space Ouputs: best state to go to next or Xnear . Benefits: 1. probabilistically complete a. If solution for path problem exists, RRT will find a soln with probability of 1 as running time goes to infinity 2. Guarantee kinematic feasibility 3. Quick to explore free space . Detractions: 1. Jerky paths created 2. Strong dependence on Neares Neighbor metric 3. Need to do collision checking for every expanded node . Approach 2: Source [3] . RRT* - works towards shortest path . | Records distance each vertex has traveled relative to parent | Closest node to parent vertex can be replaced by node with lower cost in given radius | Neighbhors can be changed higher up in the tree if a cheaper path is found. | . Disadvantages: . | More computationally expensive | . Psuedo Code: Source [3]: . Approach 3: Instead of using random point, all feasible connections are evaluated and only minimum cost paths are added to the tree. Given a cost map, we could build off it in the following manner: . | Cost functions: c_safety and c_time calculations can be found in source [4] | . To expand tree: souce [5] . | Sample a pposition uniformly at random and then sample two dimenssionaly gaussian distribution centered at the around intial path. | . Approach 4: CL-RRT . Tree expansion: grows a tree of feasible trajectories originating from the current vehicle state that attempts to reach a specified goal set [2] . Further RRT approaches are described here: https://en.wikipedia.org/wiki/Rapidly-exploring_random_tree Once we decide on a cost map approach, we can determine an algorithm to use using the cost map to create edge weights. Using heuristic algorithms such as A-star, greedy, BFS, etc. We can see if building off the avalaible methods (cost-functions, and weight functions) mentioned above into one of these algorithms, will help with making the best decision. Other choices than RRTs: . Lattice Planners: We don’t wnat to use this because we are getting a dynamic grid: . Source 1: https://www.sciencedirect.com/science/article/pii/S0968090X15003447 . Source 2: https://dspace.mit.edu/bitstream/handle/1721.1/65396/Frazzoli-2009-Real-Time%20Motion%20Planning%20With%20Applications%20to%20Autonomous%20Urban%20Driving.pdf?sequence=1&isAllowed=y . Source 3: https://theclassytim.medium.com/robotic-path-planning-rrt-and-rrt-212319121378 . Source 4: https://www.scitepress.org/Papers/2012/40334/pdf/index.html . Source 5: https://www.researchgate.net/profile/Michael-Brunner-9/publication/236847575_Hierarchical_Rough_Terrain_Motion_Planning_using_an_Optimal_Sampling-Based_Method/links/0c9605196187ad600f000000/Hierarchical-Rough-Terrain-Motion-Planning-using-an-Optimal-Sampling-Based-Method.pdf . Creating occupancy map: https://www.scitepress.org/Papers/2012/40334/pdf/index.html -> to share with perception team if they want . Control: . Current System (Severely lacking, high potential): • PurePursuit ○ Tracking algorithm enabling the vehicle’s steering wheel to smoothly adjust steering angle in relation to the curve of the given trajectory. ○ ***Possibly can breakdown this algorithm and apply similar smoothing to other aspects of our vehicle’s movement, such as velocity, acceleration, breaking. Input: Final, Unidisputed Trajectory: Set of discrete points, x(t), in a local coordinate system taken at time t0 Current Vehicle State Coordinate transform history between t0 and now . Output: Commands to hardware on vehicle . Planned System: • PurePursuit likely kept ○ Possibly expanded/using similar approaches to smoothing velocity along trajectory • Input: ○ Final, Unidisputed Trajectory: Set of discrete points (waypoints), x(t) or v(t) [Depends on RRT and how we determine cost-effective routes) • Output: ○ Precise commands to vehicle hardware ▪ Steering ▪ Pedal ▪ Break ○ Communicate with HFE team PurePursuit More PurePursuit . ", "url": "/navigator/planning/design.html#proposed-structure", "relUrl": "/planning/design.html#proposed-structure" - },"23": { + },"24": { "doc": "Interface", "title": "Interface overview", "content": " ", "url": "/navigator/interface/interface-overview.html#interface-overview", "relUrl": "/interface/interface-overview.html#interface-overview" - },"24": { + },"25": { "doc": "Interface", "title": "Table of contents", "content": ". | About Hail Bopp | Electrical overview | . The Interface subsystem represents the only code that is vehicle-specific by necessity. It is the link between software and hardware. Since your hardware is probably different than ours, then you’ll likely have to modify our interface code to suit your needs. The exception is our CARLA bridge, a simple script that spawns an ego vehicle and connects its sensors and actuators to ROS. In this overview, we’ll go over our hardware platform, Hail Bopp. ", "url": "/navigator/interface/interface-overview.html#table-of-contents", "relUrl": "/interface/interface-overview.html#table-of-contents" - },"25": { + },"26": { "doc": "Interface", "title": "About Hail Bopp", "content": "Hail Bopp includes an Electronic Power Assisted Steering (EPAS) system, which is a motor on our steering column that allows us to apply steering force programatically. Our vehicle also has front and rear Velodyne Puck (VLP-16) LiDAR sensors. These generate rich, precise 3D scans of our surroundings using 16 channels of spinning lasers. Our platform uses ZED stereo cameras to gather color images and their corresponding depth information. Stereo cams can give us limited 3D information, but they are best used in conjuction with more accurate LiDAR data. We currently use an NVIDIA Jetson AGX Xavier for our onboard computing. This is likely to change soon, as we have exceeded the power capabilities of this device. Finally, an Adafruit Metro Grand Central serves as our real-time microcontroller. This device handles time-critical services, such as releasing our steering wheel if our high-level software fails. ", "url": "/navigator/interface/interface-overview.html#about-hail-bopp", "relUrl": "/interface/interface-overview.html#about-hail-bopp" - },"26": { + },"27": { "doc": "Interface", "title": "Electrical overview", "content": ". ", "url": "/navigator/interface/interface-overview.html#electrical-overview", "relUrl": "/interface/interface-overview.html#electrical-overview" - },"27": { + },"28": { "doc": "Interface", "title": "Interface", "content": " ", "url": "/navigator/interface/interface-overview.html", "relUrl": "/interface/interface-overview.html" - },"28": { + },"29": { "doc": "Localization and Mapping", "title": "Localization and Mapping", "content": "Maintained by Will Heitman . ", "url": "/navigator/perception/mapping.html", "relUrl": "/perception/mapping.html" - },"29": { + },"30": { "doc": "Localization and Mapping", "title": "Table of contents", "content": ". | TOC | . ", "url": "/navigator/perception/mapping.html#table-of-contents", "relUrl": "/perception/mapping.html#table-of-contents" - },"30": { + },"31": { "doc": "Localization and Mapping", "title": "Octomap Module", "content": "Using the open-source Octomap library in conjunction with a particle filter, this module aims to provide a long-term, simultaneous localization and mapping solution. Target . | Translational accuracy of $\\pm 1.0$ meters at worst, $\\pm 0.25$ meters nominal in urban environment. | Heading accuracy of $\\pm 30 \\degree$ at worst, $\\pm 10\\degree$ nominal in urban environment. | Above worst-case accuracy only occurs 1% of the time. | Able to operate in case of loss from GNSS and/or IMU. | . Behavior . | On start, the module should attempt to load an existing map using the map name from /carla/world_info. | If no file exists, create an empty Octree and save this. | . | When new odometry is received (such as from an IMU), store this as an accumulated offset $(\\Delta x, \\Delta y, \\Delta \\theta)$. Update the stored Odometry message and publish it with the new offset. | When a new LiDAR point cloud is received, feed this into the particle filter. | Update all particles using the accumulated offset and Gaussian noise in a motion update. | Evaluate the probability of each particle in an observation update. | Resample all particles using their probabilities. | Compute a new robot pose using the mean and covariance of the particles. | Publish the pose as an Odometry message. | . | After the pose is updated from the LiDAR cloud, this cloud should be added to the map. | Steps 2-4 should be repeated in a loop. | A timer should prompt a visualization_msgs/Marker to be published periodically that visualizes the voxel map. | Upon termination, the octree map should be saved to a file using the name from (1). | . Progressive resolution of visualization . Assumptions . | The robot will only move along a 2D plane. That is, only 3-DOF motion will be assumed, and the localization will be calculated accordingly. | . ", "url": "/navigator/perception/mapping.html#octomap-module", "relUrl": "/perception/mapping.html#octomap-module" - },"31": { + },"32": { + "doc": "Maps", + "title": "Maps", + "content": "Maintained by Will Heitman . ", + "url": "/navigator/planning/maps.html", + + "relUrl": "/planning/maps.html" + },"33": { + "doc": "Maps", + "title": "Table of contents", + "content": ". | TOC | . ", + "url": "/navigator/planning/maps.html#table-of-contents", + + "relUrl": "/planning/maps.html#table-of-contents" + },"34": { + "doc": "Maps", + "title": "Grid maps", + "content": "All grid maps are in the base_link (vehicle) reference frame. The semantic grid extends 40 meters ahead, 20 meters behind, and 30 meters to either side of the car. ", + "url": "/navigator/planning/maps.html#grid-maps", + + "relUrl": "/planning/maps.html#grid-maps" + },"35": { + "doc": "Maps", + "title": "Semantic map", + "content": "This is a general-purpose grid map drawn from OpenDRIVE map data, where each cell is tagged with an appropriate class. | ID | Description | Class | Name | Included? | . | 0 | None/unknown. Grass, buildings, and other regions not described in the OpenDRIVE map. |   | ✅ |   | . | 1 | Driving lane | Lane | ✅ |   | . | 2 | Shoulder | Lane | ✅ |   | . | 3 | Curb | Lane | ✅ |   | . | 4 | Sidewalk | Lane | ✅ |   | . | 5 | Median | Lane | ✅ |   | . | 6 | Parking | Lane | ✅ |   | . | 11 | Stop sign | Signal | Sign_Stop |   | . | 12 | Speed limit sign | Object | Speed_30, Speed_60, Speed_90 |   | . | 13 | Traffic light | Signal | Signal_3Light_Post01 |   | . | 21 | Crosswalk | Object | CContinentalCrosswalk |   | . ", + "url": "/navigator/planning/maps.html#semantic-map", + + "relUrl": "/planning/maps.html#semantic-map" + },"36": { "doc": "OpenDrivePy", "title": "OpenDrivePy", "content": "Maintained by Will Heitman . ", "url": "/navigator/opendrivepy.html", "relUrl": "/opendrivepy.html" - },"32": { + },"37": { "doc": "OpenDrivePy", "title": "Table of contents", "content": ". | TOC | . ", "url": "/navigator/opendrivepy.html#table-of-contents", "relUrl": "/opendrivepy.html#table-of-contents" - },"33": { + },"38": { "doc": "OpenDrivePy", "title": "Element tree", "content": "Map ├── get_route(): Lane[] ├── header: Header (contains north, x0, and other geo ref data) ├── shapes: STRTree ├── shapes: STRTree ├── shapes: STRTree ├── roads: Road[] │ └── Road 1 │ ├── name: str │ ├── id: int │ ├── length: float │ ├── junction: int │ ├── speed_limit: float (m/s, should convert otherwise) │ ├── type: RoadType │ ├── next: Road | Junction │ ├── prev: Road | Junction │ ├── refline: LineString │ ├── lane_offset: LineString │ └── sections: [LaneSection] │ ├── s: float │ ├── signals: Signal[] (speed limit signs, traffic lights, ...) │ └── lanes: Lane[] │ ├── Lane A │ │ ├── id: int │ │ ├── lsec: LaneSection (parent reference) │ │ ├── road: Road (grandparent reference) │ │ ├── type: LaneType (\"shoulder\", \"sidewalk\", \"driving\", ...) │ │ ├── predecessors: Lane[] │ │ ├── successors: Lane[] │ │ └── shape: Polygon │ └── Lane B │ └── ... ├── controllers: Controller[] └── junctions: Junction[] . Above: Lane polygons. Errors with the rendering of curved lanes and lane ocause some imperfection. Above: Drivable map using prepared geometry . Above: Drivable map using STRTree . ", "url": "/navigator/opendrivepy.html#element-tree", "relUrl": "/opendrivepy.html#element-tree" - },"34": { + },"39": { "doc": "Perception", "title": "Perception overview", "content": "Maintained by Ragib Arnab . ", "url": "/navigator/perception/perception-overview.html#perception-overview", "relUrl": "/perception/perception-overview.html#perception-overview" - },"35": { + },"40": { "doc": "Perception", "title": "Table of contents", "content": ". | darknet_inference | obstacle_detection_3d | obstacle_classes | obstacle_drawer | lidar_fusion | lidar_obstacle_detector | . The perception component of the system takes the data from various sensors and extracts meaningful information for downstream components such as planning. Some of the tasks that are core parts of the perception include, but not limited to: . | Localization and state estimation | Obstacle and scene classifiation | Obstacle tracking and prediction | . In this page we will go each individual packages that is part of the perception component. A lot of the packages within perception are “in-progress” just as with most other packages within our system. As this project progresses, we will update the existing packages as well as add new ones to meet the growing demands of our autonomous system. ", "url": "/navigator/perception/perception-overview.html#table-of-contents", "relUrl": "/perception/perception-overview.html#table-of-contents" - },"36": { + },"41": { "doc": "Perception", "title": "darknet_inference", "content": "The darknet_inference package contains Python tools to build and run Darknet-based object detection models in ROS 2. The standard model that is used is YOLOv4 which can achieve real-time inference on a modern GPU with good overall accuracy. There is also an option to use the YOLOv4-tiny model to increase the inference rate but with a sacrifice to accuracy. The node for this package subscribes to a RGB image message topic and outputs 2D bounding box predictions for each class of object in its own message formats. In this current version of navigator, all the detections for the vehicle is performed in this node, which includes detecting cars and pedestrians as well as finding landmarks such as stop signs and fire hydrants. All these detections are also processed within the node itself by using parameters such as object confidence threshold and non-maximum suppression (NMS) threshold to filter out the unwanted detections. ", "url": "/navigator/perception/perception-overview.html#darknet_inference", "relUrl": "/perception/perception-overview.html#darknet_inference" - },"37": { + },"42": { "doc": "Perception", "title": "obstacle_detection_3d", "content": "This package takes as input the 2D detections along with 3D sensing data from lidars and depth camera to output 3D bounding boxes. 3D detection are required for behavior and planning components of our system. Currently the code simply backprojects the 2D bounding boxes into 3D using information and extends the boxes into a cuboid based on the object’s class. This is a naive approach given that the orientation information of the cuboids will be the same as the vehicle and that the lengths of the objects are fixed. The algorithm is a placeholder and will be replaced by an actual 3-D object detection algorithm in the future. ", "url": "/navigator/perception/perception-overview.html#obstacle_detection_3d", "relUrl": "/perception/perception-overview.html#obstacle_detection_3d" - },"38": { + },"43": { "doc": "Perception", "title": "obstacle_classes", "content": "Contains the enumeration definition for the different classes of obstacles. ", "url": "/navigator/perception/perception-overview.html#obstacle_classes", "relUrl": "/perception/perception-overview.html#obstacle_classes" - },"39": { + },"44": { "doc": "Perception", "title": "obstacle_drawer", "content": "A simple visualization package that takes the 3D bounding box outputs and produces visualization messages that can be depicted in RViz. ", "url": "/navigator/perception/perception-overview.html#obstacle_drawer", "relUrl": "/perception/perception-overview.html#obstacle_drawer" - },"40": { + },"45": { "doc": "Perception", "title": "lidar_fusion", "content": "This package fuses the 2 different lidar sources within our system into a single point cloud that will be registered into the same frame (base-link) within the system transform tree. The package also performs basic point cloud filtering. ", "url": "/navigator/perception/perception-overview.html#lidar_fusion", "relUrl": "/perception/perception-overview.html#lidar_fusion" - },"41": { + },"46": { "doc": "Perception", "title": "lidar_obstacle_detector", "content": "This package is tasked with detecting low-level obstacles around the vehicle for the purpose of collision prevention. The node takes as input a point cloud and output zones around the vehicle for low-level obstacles. ", "url": "/navigator/perception/perception-overview.html#lidar_obstacle_detector", "relUrl": "/perception/perception-overview.html#lidar_obstacle_detector" - },"42": { + },"47": { "doc": "Perception", "title": "Perception", "content": " ", "url": "/navigator/perception/perception-overview.html", "relUrl": "/perception/perception-overview.html" - },"43": { + },"48": { "doc": "Perception and Prediction Design Document (draft)", "title": "Perception and Prediction Design Document (draft)", "content": "Maintained by Ashwin . ", "url": "/navigator/perception/perception_new.html", "relUrl": "/perception/perception_new.html" - },"44": { + },"49": { "doc": "Perception and Prediction Design Document (draft)", "title": "Table of contents", "content": ". | System Overview . | Current System: . | Prediction: | . | Planned System: . | Perception: | Prediction: | . | Proposed structures for Phase 1: . | 3D/2D bounding boxes: | System overview for Dynamic Environment Prediction | Proposed structure for Dynamic Environment Prediction | . | . | . ", "url": "/navigator/perception/perception_new.html#table-of-contents", "relUrl": "/perception/perception_new.html#table-of-contents" - },"45": { + },"50": { "doc": "Perception and Prediction Design Document (draft)", "title": "System Overview", "content": "Current System: . Prediction: . - Zones in place of dynamic object detection - Acts as a safety net cast over objects in view of the vehicle - Car \"reacts\" to zone/wall proximity and zone speed argument - Slows down to minimum speed argument, regardless if there are multiple zones - Primitive - Unable to further expand implementation - Zone algorithm highlighted more in depth in behavior planning and control document . Planned System: . Perception: . Phase 1: . | 3D/2D bounding boxes (tracked) . | Static occupancy grid . | . Phase 2: . | Landmark detection (Stop lights priority) . | Semantic encoding . | Map masks: Stop lines, Cross walks . | . Phase 3: . | Tune models within simulator . | Eventually deploy and test on vehicle . | . Prediction: . Phase 1: . | Physics-based prediction implemented . | Treats cars like particles (acceleration & velocity) . | Dynamic occupancy grid . | . Phase 2: . | ML-based occupancy grid (from physics-based) . | Non-sequential learning . | Sequential learning . | Recurrent Neural Nets . | . Dynamic Bayesian Network . Phase 3: . | ML refined . | Map priors . | Deployed and tested on vehicle . | . **** Insert first image ** . Proposed structures for Phase 1: . 3D/2D bounding boxes: . 3D: . Estimating 3D bounding boxes based on 2D images: . A method for 3D object detection using 2D images. This method involves utilizing a deep convolutional network to obtain relatively stable 3D object properties, and utilize this along with some geometric constraints provided by a 2d bounding box (would probably need to figure this out using something like YOLOv3) in order to construct a 3D bounding box for the corresponding object. Given the pose of the object in the camera coordinate frame (R, T) ∈ SE(3) and the camera intrinsic matrix K, the projection of a 3D point Xo = [X, Y, Z, 1]^T in the object’s coordinate frame into the image x = [x, y, 1]T is: x = K [R T] Xo [1] . 2D: . 2D object detection from a BEV representation (Bird’s Eye View, looking down from the Z axis) of our pseudo-lidar point cloud data may be more efficient than processing a generic 3D convolution. This architecture may also include semantic segmentation, effectively enabling us to accomplish landmark detection as well without any additional computation. Can be a solution for stereo-images. Depth correction w/ existing LiDAR sensors . 2D BEVDetNet Object Detection . Pseudo-LiDAR . System overview for Dynamic Environment Prediction . Our system uses point clouds for dynamic environment prediction. We use a ConvLSTM architecture intended for video frame prediction to instead predict the local environment surrounding an autonomous agent across future time steps. For this purpose, we adapt the PredNet architecture designed for video frame prediction in autonomous driving scenes. The ConvLSTM is expected to learn an internal representation of the dynamics within the local environment from occupancy grid data. The grid inputs are generated from LiDAR measurement recordings in the KITTI dataset taken across a variety of urban scenes [1]. Proposed structure for Dynamic Environment Prediction . Inputs for Dynamic Environment Prediction . | Point Cloud | . Produces for Dynamic Environment Prediction . | Ground Segmentation . | Occupancy grid and DOGMA . | PredNet (Neural Network Architecture) . | . Dynamic Environment Prediction does not handle… . | More research needed… | . Dynamic Environment Prediction: Ground Segmentation . Prior to generating an occupancy grid, the ground must be segmented and removed from the LiDAR point cloud. Markov Random Field (MRF) algorithm that exploits local spatial relationships, avoiding the assumption of a planar ground [2][1]. Dynamic Environment Prediction: Dynamic Occupancy Grid Maps (DOGMas) . A DOGMa is an evidential grid containing both occupancy and dynamic state information (e.g., velocity). We generate DOGMas via the procedure outlined by Nuss et al. [4]. There are two parallel processes that occur: occupancy grid updates and cell-wise velocity estimates [1]. Occupancy Grids . We consider DST-based occupancy grids computed from LiDAR measurements as detailed by Nuss et al. [4]. DST deals with a set of exhaustive hypotheses formed from a frame of discernment and the associated belief masses. In the case of an occupancy grid, our frame of discernment is: Ω = {F, O}, where F is free space and O is occupied space. Thus, the set of hypotheses is: {∅, {F }, {O}, {F, O}}. The null set ∅ is impossible in this context as a cell physically cannot be neither occupied nor unoccupied. Thus, our exhaustive set of hypotheses is: {{F }, {O}, {F, O}}. The sum of the belief masses over the possible hypotheses for each individual cell must equal one by definition, akin to probabilities [1]. Velocity Estimation . To incorporate dynamics, we estimate the velocity for each cell. The velocity estimates use a DST approximation for a probability hypothesis density filter with multi-instance Bernoulli (PHD/MIB) [5]. DST allows for the particle filter to run more efficiently by initializing particles only in cells with occupied masses above a specified threshold, avoiding occluded regions without measurements[1]. Dynamic Environment Prediction: Neural Network Architecture . We repurpose the PredNet architecture to learn the spatial and temporal representation of the environment by training it on occupancy grids instead of images. The convolutional layers exploit contextual information to correlate the occupied cells, removing the cell independence assumption [6]. The self-supervised nature of sequential data prediction is advantageous as human-labeled LiDAR data is expensive to obtain [6]. In this framework, the labels are simply the input environment representation (grids) at a later time instance. Although the original PredNet model was designed for video data, we demonstrate that the architecture can be re-used in the LiDAR setting [1]. Dynamic Environment Prediction: Experiments . | Dataset Generation . | LiDAR Measurement Grids . | The KITTI HDL-64E Velodyne LiDAR dataset was augmented for use in occu- pancy grid prediction [7]. The dataset contains a variety of urban road scenes in Karlsruhe, Germany. We use 35, 417 frames (138 driving sequences) for training, 496 frames (3 driving sequences) for validation, and 2, 024 frames (7 driving sequences) for testing. Velodyne LiDAR point cloud measurements are obtained at 10 Hz. | Each LiDAR point cloud is filtered to remove the points corresponding to the ground as described in Section II. Then, a simple form of ray-tracing is performed to determine the free space between a LiDAR measurement and the ego vehicle. Each resulting local grid is centered at the ego vehicle GPS coordinate position. The shorter grid range is acceptable for slower speeds in urban settings, as is the case in the KITTI dataset [7][1]. | Dynamic Occupancy Grid Maps . | Dynamic Occupancy Grid Maps: The DOGMa’s occupancy and velocity information is computed from the LiDAR data as outlined in Section II. The velocities are then filtered to remove static measurements according to the cell-wise Mahalanobis distance: τ = vT P v, where v is the velocity vector and P is the cell’s covariance matrix as computed from the particles [21]. Cells with occupancy masses below a threshold are also removed. The velocities are then normalized to the range [−1, 1] and stacked with either (1) the pignistic probability (Eq. (5)) or (2) the DST mass (Eq. (2) and Eq. (3)) occupancy grids, forming the input to the network. [1] | . | . | PredNet Experiments . | PredNet was trained and tested on an NVIDIA GeForce GTX 1070 GPU. At test time, one sequence (15 predictions totaling 1.5 s ahead) took on average 0.1 s to run. [1] | . | . ", "url": "/navigator/perception/perception_new.html#system-overview", "relUrl": "/perception/perception_new.html#system-overview" - },"46": { + },"51": { "doc": "Planning", "title": "Costmaps", "content": "Here are the costmaps that we should calculate at minimum, along with their justification: . ", "url": "/navigator/planning/planning-overview.html#costmaps", "relUrl": "/planning/planning-overview.html#costmaps" - },"47": { + },"52": { "doc": "Planning", "title": "Drivable area", "content": "This describes a surface that the car is allowed to drive over, mainly lanes, parking spaces, and intersections. We can expand this drivable area if the car’s current options are exhausted. For example, the default drivable area may only include lanes that match the car’s current driving direction, but this region can be expanded to include lanes with oncoming traffic if the current region is blocked. Justification: The car should only be allowed to drive on “drivable” surfaces: no sidewalks, lawns, etc. Suggested format: 0.4m cell size, 40m range. Above: Example where drivable region expansion may be useful. Credit: CARLA Leaderboard. ", "url": "/navigator/planning/planning-overview.html#drivable-area", "relUrl": "/planning/planning-overview.html#drivable-area" - },"48": { + },"53": { "doc": "Planning", "title": "Predicted occupancy", "content": "Occupancy grids are a common concept in robotics used to describe obstacles. The world is divided into cells. If a given cell contains an obstacle, then it is marked as occupied. Using machine learning, we can generate occupancy grids not just for the present ($t=0$), but also for the future (such as $t=3s$). For a simple costmap that compresses all temporal considerations into the present, we can simply add the predicted occupancies across all frames, creating a single costmap for both the current and future occupancies. Justification: The car should not run into anything. Suggested format: 0.4m, 20m range minimum, 40m ideal. ", "url": "/navigator/planning/planning-overview.html#predicted-occupancy", "relUrl": "/planning/planning-overview.html#predicted-occupancy" - },"49": { + },"54": { "doc": "Planning", "title": "Distance to route & goal", "content": "This is a combined costmap that describes both how far the car is from the route and from the goal. Justification: The car should drive along the route until the goal is reached. ", "url": "/navigator/planning/planning-overview.html#distance-to-route--goal", "relUrl": "/planning/planning-overview.html#distance-to-route--goal" - },"50": { + },"55": { "doc": "Planning", "title": "Costmap specifications", - "content": ". | All costmaps should be in the map frame, aligned with the x/y axes of the map. This eliminates the need to perform costly transforms. | All costmaps should have resolutions (cell sizes) that are multiples of the same base resolution. Example: 0.4, 0.8, and 1.6 meters. This allows them to be cleanly scaled. | The costmaps do not necessarily need to share an origin nor size, though their sum will only be accurate in the region where they align. | . ", + "content": ". | All costmaps should be in the base_link frame, centered on the vehicle. | All costmaps should have resolutions (cell sizes) that are multiples of the same base resolution. Example: 0.4, 0.8, and 1.6 meters. This allows them to be cleanly scaled. | The costmaps do not necessarily need to share an origin nor size, though their sum will only be accurate in the region where they align. | . ", "url": "/navigator/planning/planning-overview.html#costmap-specifications", "relUrl": "/planning/planning-overview.html#costmap-specifications" - },"51": { + },"56": { "doc": "Planning", "title": "Planning", "content": "The car should follow three instructions, in order of priority: . | Don’t run into anything. | Drive forward along a route until the goal is reached. | Obey traffic laws. | . The car should be rewarded for obeying these three instructions, and the Planning system’s objective should be to maximize this reward. To help the car make appropriate decisions, we can feed it “costmaps” that represent the reward that the car will receive if it drives through a given spot on the map. Each costmap might represent a specific quality (the drivable surfaces near the car, for example), and we can simply take the weighted sum of each costmap to generate a hollistic overview for the car. Keep in mind that “cost” and “reward” are really the same concept. The car’s goal is to select a path that moves through regions of the greatest reward, a.k.a. of the least cost. The more costmaps we sum together and the more carefully we select the weights for the sum, the better our car will be at making decisions. ", "url": "/navigator/planning/planning-overview.html", "relUrl": "/planning/planning-overview.html" - },"52": { + },"57": { "doc": "Schematics", "title": "Schematics", "content": " ", "url": "/navigator/interface/schematics.html", "relUrl": "/interface/schematics.html" - },"53": { + },"58": { "doc": "Schematics", "title": "Main Nova Schematic", "content": ". ", "url": "/navigator/interface/schematics.html#main-nova-schematic", "relUrl": "/interface/schematics.html#main-nova-schematic" - },"54": { + },"59": { "doc": "Schematics", "title": "Power Source Schematics", "content": ". ", "url": "/navigator/interface/schematics.html#power-source-schematics", "relUrl": "/interface/schematics.html#power-source-schematics" - },"55": { + },"60": { "doc": "Schematics", "title": "USB Hub Schematics", "content": ". ", "url": "/navigator/interface/schematics.html#usb-hub-schematics", "relUrl": "/interface/schematics.html#usb-hub-schematics" - },"56": { + },"61": { "doc": "Schematics", "title": "Adafruit Grand Central Schematics", "content": ". ", "url": "/navigator/interface/schematics.html#adafruit-grand-central-schematics", "relUrl": "/interface/schematics.html#adafruit-grand-central-schematics" - },"57": { + },"62": { "doc": "Schematics", "title": "CAN Bus Systems", "content": ". ", "url": "/navigator/interface/schematics.html#can-bus-systems", "relUrl": "/interface/schematics.html#can-bus-systems" - },"58": { + },"63": { "doc": "Schematics", "title": "EPAS", "content": ". ", "url": "/navigator/interface/schematics.html#epas", "relUrl": "/interface/schematics.html#epas" - },"59": { + },"64": { + "doc": "Semantic segmentation", + "title": "Semantic segmentation", + "content": "Maintained by Will Heitman . ", + "url": "/navigator/perception/segmentation.html", + + "relUrl": "/perception/segmentation.html" + },"65": { + "doc": "Semantic segmentation", + "title": "Table of contents", + "content": ". | TOC | . ", + "url": "/navigator/perception/segmentation.html#table-of-contents", + + "relUrl": "/perception/segmentation.html#table-of-contents" + },"66": { + "doc": "Semantic segmentation", + "title": "Class dictionary", + "content": "Our semantic segmentation model is trained on the Cityscapes Dataset. | Description | Class ID (int) | RGB | Unpacked | . | Road | 0 | (128, 64, 128) | 4286595200 | . | Sidewalk | 1 | (244, 35, 232) | 4294190056 | . | Building (overwritten by wall) | 2 |   |   | . | Wall | 3 | (102,102,156) | ? | . | Fence (overwritten by wall) | 4 |   |   | . | Pole | 5 | (153, 153, 153) | 4288256409 | . | Traffic light | 6 | (250, 170, 30) | 4294617630 | . | Traffic sign | 7 | (220, 220, 0) | 4292664320 | . | Vegetation | 8 | (107, 142, 35) | ? | . | Terrain | 9 | (145, 170, 100) | 4287736420 | . | Sky | 10 | (70, 130, 180) | ? | . | Person | 11 | (220, 20, 60) | ? | . | Rider (overwritten by Car) | 12 |   |   | . | Car | 13 | (0, 0, 142) | 4278190222 | . | Truck (overwritten by Car) | 14 |   |   | . | Bus (overwritten by Car) | 15 |   |   | . | Train (overwritten by Car) | 16 |   |   | . | Motorcycle (overwritten by Bicycle) | 17 |   |   | . | Bicycle | 18 | (119, 11, 32) | 4285991711 | . import struct r,g,b = 119,11,31 a = 255 # always unpacked = struct.unpack('I', struct.pack('BBBB', b, g, r, a))[0] # 4285991711 . ", + "url": "/navigator/perception/segmentation.html#class-dictionary", + + "relUrl": "/perception/segmentation.html#class-dictionary" + },"67": { "doc": "Sensing", "title": "Sensing overview", "content": " ", "url": "/navigator/sensing/sensing-overview.html#sensing-overview", "relUrl": "/sensing/sensing-overview.html#sensing-overview" - },"60": { + },"68": { "doc": "Sensing", "title": "Table of contents", "content": ". The Sensing system is responsible for processing raw sensor data into a usable form for the Perception system. For example, raw LiDAR data from our front and rear sensors is merged into a single reference frame, downsampled, and cropped to remove points along the vehicle itself (points of our vehicle’s doors, for example). More info to come! But our filters aren’t reinvinting the wheel. ", "url": "/navigator/sensing/sensing-overview.html#table-of-contents", "relUrl": "/sensing/sensing-overview.html#table-of-contents" - },"61": { + },"69": { "doc": "Sensing", "title": "Sensing", "content": " ", "url": "/navigator/sensing/sensing-overview.html", "relUrl": "/sensing/sensing-overview.html" - },"62": { + },"70": { "doc": "Simulation", "title": "Simulation overview", "content": "Maintained by Connor Scally & Daniel Vayman . ", "url": "/navigator/simulation/simulation-overview.html#simulation-overview", "relUrl": "/simulation/simulation-overview.html#simulation-overview" - },"63": { + },"71": { "doc": "Simulation", "title": "Table of contents", "content": ". | Simulation Enviroment | Launching the simulator & running Navigator: | Using the Simulator: | Troubleshooting: | Sourcing Foxy Automatically in Bash: | . Before demonstrating our codebase on the vehicle, in the real world, we must first test our stack in a virtual one. The following documentation outlines essential CARLA usage and syntax, to allow for simulating our stack in a virtual enviroment. Nova utilizes CARLA for virtualization. For further information on CARLA, and to learn more about advanced usage, please see the following links: . | https://carla.org/ | https://carla.readthedocs.io/en/latest/ | . ", "url": "/navigator/simulation/simulation-overview.html#table-of-contents", "relUrl": "/simulation/simulation-overview.html#table-of-contents" - },"64": { + },"72": { "doc": "Simulation", "title": "Simulation Enviroment", "content": ". | Prerequisites: . | CARLA Simulator: Please follow the instructions in the above links to install CARLA on your chosen operating system | Navigator: Please see our GitHub page for the latest releases of Navigator | RVIZ (Or an equivalent ROS visualizer) | ROS2 | Dependencies for the above: Self-explanatory, Navigator comes with most of what you need, CARLA may not, do not forget to check! | . | . ", "url": "/navigator/simulation/simulation-overview.html#simulation-enviroment", "relUrl": "/simulation/simulation-overview.html#simulation-enviroment" - },"65": { + },"73": { "doc": "Simulation", "title": "Launching the simulator & running Navigator:", "content": ". | Launching CARLA: . | Your first step should be to navigate to your CARLA directory and launch CARLA with the CARLAUE4.sh script with the -RenderOffScreen flag. If you are on a unix system, the command will look like this: | . $ /home/share/carla/CarlaUE4.sh -RenderOffscreen . | The “RenderOffscreen” flag hides the rendering window, which saves some resources. See here for more details . | Launching RVIZ (within our Docker container): . | Open a new terminal window. | Navigate to the root directory of Navigator . | Enable Docker to launch GUI programs . $ xhost + . | Run our docker container start script. (If first time running container, refer to step 3) . $ ./start.sh . | Source the setup script via a command like: . install/setup.bash . | Run: rviz2 | Select File followed by Open Config Select default.rviz from the share folder. It is recommended that you have your own copy of this as well for your own configuration. | . | Launching Navigator: . | Open a new terminal window. | Navigate to the root directory of Navigator. | Run the docker container ./start.sh . | Run source /install/setup.bash (if you have bash sourcing ROS automatically (see below), that works too) . | Run ros2 launch carla_interface carla-lite.launch.py . | Check RVIZ and terminal output. The sim_bridge will publish sensor data just as if you were driving on campus, and it will similary accept commands from our standard topics. As of writing, our custom bridge publishes: . | . | GNSS (GPS) | IMU | Front and rear Lidar (not fully functional) | Front RGB camera | Front depth camera | CARLA ground truths for | Car’s odometry (position, orientation, speed) | CARLA virtual bird’s-eye camera (/carla/birds_eye_rgb) | . The most up-to-date information on our bridge’s capabilities can be found at the top of the script itself. | . ", "url": "/navigator/simulation/simulation-overview.html#launching-the-simulator--running-navigator", "relUrl": "/simulation/simulation-overview.html#launching-the-simulator--running-navigator" - },"66": { + },"74": { "doc": "Simulation", "title": "Using the Simulator:", "content": ". | You can control our ego vehicle with ros2 run manual_control manual_control_node . | At the moment, this only supports keyboard control through NoMachine or similar, not SSH. | If you get a “pynput” error, try running pip3 install pynput. | . | You can change a number of simulation settings by editing our script’s contants (here). | Don’t forget to rebuild the package or use colcon build --symlink-install (recommended). | ROS param support in the works. | . | . ", "url": "/navigator/simulation/simulation-overview.html#using-the-simulator", "relUrl": "/simulation/simulation-overview.html#using-the-simulator" - },"67": { + },"75": { "doc": "Simulation", "title": "Troubleshooting:", "content": ". | If you get a “pynput” error, try running pip3 install pynput. | If you get a CARLA segmentation fault, it’s likely you just need to restart CARLA. This will be fixed… eventually. This should only happen after starting the bridge 10 times or so, and should not happen while the bridge is running. | If CARLA gives you a SIGFAULT error attach the -carla-rpc-port=N where N = your favorite (Not in use) port number. | . ", "url": "/navigator/simulation/simulation-overview.html#troubleshooting", "relUrl": "/simulation/simulation-overview.html#troubleshooting" - },"68": { + },"76": { "doc": "Simulation", "title": "Sourcing Foxy Automatically in Bash:", "content": ". | Open your terminal | Write the command –> gedit ~/.bashrc (or nano, whatever really) | Go under the last line line and write –> source /opt/ros/foxy/setup.bash | Save and exit | Now with every new shell you open, it will source automatically | . ", "url": "/navigator/simulation/simulation-overview.html#sourcing-foxy-automatically-in-bash", "relUrl": "/simulation/simulation-overview.html#sourcing-foxy-automatically-in-bash" - },"69": { + },"77": { "doc": "Simulation", "title": "Simulation", "content": " ", "url": "/navigator/simulation/simulation-overview.html", "relUrl": "/simulation/simulation-overview.html" - },"70": { + },"78": { "doc": "System overview", "title": "System overview", "content": "Maintained by Will Heitman . ", "url": "/navigator/system-overview.html", "relUrl": "/system-overview.html" - },"71": { + },"79": { "doc": "System overview", "title": "Table of contents", - "content": ". | Design | Subsystems . | Example | . | . ", + "content": ". | Design . | About nodes and topics | . | Subsystems | Cost maps | Topics | . ", "url": "/navigator/system-overview.html#table-of-contents", "relUrl": "/system-overview.html#table-of-contents" - },"72": { + },"80": { "doc": "System overview", "title": "Design", - "content": "Navigator is designed to be: . | Simple, with components that are easy to use an extend . | When a more powerful but complex algorithm is used, a simpler alternative should also be present | . | Modular, with nodes that can be swapped, added, and updated with the help of ROS2 . | Since nodes are all built using standard C++ and Python libraries, code is future-proofed. | . | Open source, with all of our code licensed under the highly permissable MIT license . | Our dependencies are also open-source | . | . ", + "content": "Navigator is designed to be: . | Simple, with components that are easy to use an extend . | When a more powerful but complex algorithm is used, a simpler alternative should also be present | . | Modular, with nodes that can be swapped, added, and updated with the help of ROS2 . | Since nodes are all built using standard C++ and Python libraries, code is future-proofed. | . | Open source, with all of our code licensed under the highly permissable MIT license . | Our dependencies are also open-source | . | . About nodes and topics . Navigator is built upon ROS2, a communications framework where individual executables called “nodes” exchange messages throguh “topics.” A node can either subscribe to a topic or publish to it. In this fashion, individual nodes form a dense network where everything from camera streams to steering commands are passed from one node to the next. Nodes can be grouped into packages. Packages are then grouped in workspaces. Navigator itself is a ROS workspace. It contains many packages, and each package contains at least one node. Using ROS2, one node can gather raw LiDAR data from a sensor, where it publishes the pointcloud as a PointCloud2 message to a topic called /lidar/raw. Another node can then subscribe to /lidar/raw, filter the data, and publish the result to /lidar/filtered. To learn more about ROS, watch this lecture by Katherine Scott, a developer advocate at Open Robotics. <!– ## Subsystems . Navigator is split into five main subsystems: . | Sensing, where raw sensor data from cameras, GNSS, and more is filtered before being passed along | Perception, which uses the filtered sensor data to build a rich understanding of the car’s surroundings | Planning, which uses this rich understanding, plus the desired destination, to decide how the car should act on a high level | Controls, where the desired action is compared to the car’s current state and low-level action is calculated | Interface, where the low-level action is sent to the steering wheel and pedals. –> | . ", "url": "/navigator/system-overview.html#design", "relUrl": "/system-overview.html#design" - },"73": { + },"81": { "doc": "System overview", "title": "Subsystems", - "content": ". Navigator is split into five main subsystems: . | Sensing, where raw sensor data from cameras, GNSS, and more is filtered before being passed along | Perception, which uses the filtered sensor data to build a rich understanding of the car’s surroundings | Planning, which uses this rich understanding, plus the desired destination, to decide how the car should act on a high level | Controls, where the desired action is compared to the car’s current state and low-level action is calculated | Interface, where the low-level action is sent to the steering wheel and pedals. | . We also have some important code to support testing, visualization, and simulation. Simulation plays a big role in our development, and you can find an overview of it here. Example . Our sensing system takes in a red blob from our front camera and does some white balancing to make the image more clear. The perception system identifies this red blob as a stop sign and generates a bounding box with the coordinates of the stop sign relative to the car. The planning system determines that we must set our speed to zero at the stop sign. The controls system notes that our car is still moving, and calculates that we must decelerate a certain amount. Finally, our actuation system converts this desired deceleration into a brake pedal command, which is sent out to the pedal’s motor. ", + "content": "We can divide Navigator’s nodes into four groups. The sensing subsystem takes raw sensor data and publishes them as Image messages, PointCloud2 messages, Imu messages, and so on. This subsystem also include sensor filters, which subscribe to raw data and publish their filtered results. The perception subsystem draws inferences from the sensor data, including the location of pedestrians, our position on the map, and the predicted motion of surrounding vehicles. Nodes in this subsystem often publish their results as cost maps. The planning subsystem takes our perception results and decides what our vehicle should do. This subsystem handles both high-level decisions (Should we pass a car that’s stopped in the road?) and low-level ones (How far should we press the throttle pedal to reach our desired speed?). The interface subsystem is the link between our software and hardware. It includes nodes that communicate with our steering hardware, our microcontroller, and more. Both the sensing and interface subsystems are vehicle-specific, which means that they need to be configured to suite each individual vehicle. At Nova, we have separate configurations for simulated driving and real-world use. ", "url": "/navigator/system-overview.html#subsystems", "relUrl": "/system-overview.html#subsystems" - },"74": { + },"82": { + "doc": "System overview", + "title": "Cost maps", + "content": "During execution, Navigator calculates several cost maps, which are grid-based maps of our surrounding area that describe where our car should or should not drive. Each cell in the grid is assigned a cost. The higher the cost, the less likely our car will generate a path that moves through the cell. This results in paths that weave their way through only low-cost cells. If no low-cost cells are available, the car stops and waits. We calculate and use multiple cost maps, each one representing a unique factor to consider. For example: . | Our occupancy grid generator describes the location of objects (cars, people, curbs). | Our prediction network (PredNet) node describes the future location of obstacles. | Our red light detector marks intersections as high-cost regions if the light is red. | Our map manager assigns costs based on how far a cell is from the route and from the goal. | . We add as many of these layers together to form a single, holisitic costmap that our motion planner uses as its input. Above: Cost map dimensions . Cost maps should be in the base_link (vehicle) reference frame. They should extend 40 meters in front and to the side of the car and 20 meters behind, forming a total area of 80 x 60 meters. Cells should have a side length of either 0.2, 0.4, 0.8, or 1.6 meters. In the above example, each image is 200 x 150 pixels, representing a cost map layer with a resolution of 0.4 meters/cell. Clockwise from top left: Current occupancy, junction cost (due to a stop sign), route distance, and drivable area. ", + "url": "/navigator/system-overview.html#cost-maps", + + "relUrl": "/system-overview.html#cost-maps" + },"83": { + "doc": "System overview", + "title": "Topics", + "content": ". | /lidar/fused: Raw LiDAR fused together to create a 360-degree picture. Otherwise unfiltered. | /lidar/filtered: Filtered LiDAR, with ground points removed. | /grid/drivable | /grid/route_distance | /grid/occupancy/current: Only the current occupancy grid. | /grid/occupancy/combined: Both the current and all future prediction occupancy grids, summed together. | . ", + "url": "/navigator/system-overview.html#topics", + + "relUrl": "/system-overview.html#topics" + },"84": { + "doc": "Tricks", + "title": "Tricks", + "content": "Maintained by Nova members . ", + "url": "/navigator/contributing/tricks.html", + + "relUrl": "/contributing/tricks.html" + },"85": { + "doc": "Tricks", + "title": "Table of contents", + "content": ". | TOC | . ", + "url": "/navigator/contributing/tricks.html#table-of-contents", + + "relUrl": "/contributing/tricks.html#table-of-contents" + },"86": { + "doc": "Tricks", + "title": "Tools", + "content": ". | You can get the publishing frequency of a topic with $ ros2 topic hz [topic_name] | Show a graph of all current topics and nodes with $ rqt_graph | VS Code’s “Remote - SSH” extension is a good way to develop remotely on the Quad. Files, terminals, and more all appear as though you were working locally on the Quad. | Other useful VS Code extensions include Prettier, GitLens, Doxygen Documenttion Generator (C++), autoDocstring (Python), and the C/C++ entension pack. | . ", + "url": "/navigator/contributing/tricks.html#tools", + + "relUrl": "/contributing/tricks.html#tools" + },"87": { + "doc": "Tricks", + "title": "Other", + "content": ". | ROS Services are alternatives to publishers/subscribers. They return results only when requested by a Client. | . ", + "url": "/navigator/contributing/tricks.html#other", + + "relUrl": "/contributing/tricks.html#other" + },"88": { "doc": "Troubleshooting", "title": "Troubleshooting", "content": "Maintained by Nova members . ", "url": "/navigator/contributing/troubleshooting.html", "relUrl": "/contributing/troubleshooting.html" - },"75": { + },"89": { "doc": "Troubleshooting", "title": "Table of contents", "content": ". | “New publisher discovered on this topic, offering incompatible QoS” . | Solution | . | “RuntimeError: trying to create rpc server for traffic manager…” | When running the leaderboard evaluator: “No module named ‘agent’” . | Solution: Ensure that there isn’t a typo in the --agent flag to leaderboard_evaluator.py. As of writing, this is in leaderboard.bash. | . | “The RMW implementation has been specified as…” . | Solution | . | . “New publisher discovered on this topic, offering incompatible QoS” . [WARN] [1669075701.737584987] [leaderboard_node]: New publisher discovered on this topic, offering incompatible QoS. No messages will be received from it. Last incompatible policy: DURABILITY_QOS_POLICY . A warning similar to the above example will appear when a publisher and subscriber attempt to exchange messages with incompatible quality of service QoS policies. Solution . Edit the QoS policy of either the relevant publisher or subscriber so that the two can “speak” to each other. For more information on QoS in ROS2, including compatibility between policies, see here. “RuntimeError: trying to create rpc server for traffic manager…” ... File \"/workspace/leaderboard/leaderboard/leaderboard_evaluator.py\", line 83, in __init__ self.traffic_manager = self.client.get_trafficmanager(args.traffic_manager_port) RuntimeError: trying to create rpc server for traffic manager; but the system failed to create because of bind error. This is caused when a CARLA client attempts to connect to CARLA on a port that is already being used. This is either because: . | Another user is currently using the simulator . | In which case you should change your port by using the --traffic_manager_port or similar, depending on which script you’re running | . | An earlier CARLA client has died before it freed its port, and so there is some orphaned Python process on the system that is using up the RPC port. One brute force method is to run sudo pkill -9 python, but this is a very ugly solution. | . When running the leaderboard evaluator: “No module named ‘agent’” . As of 12 Nov ‘22 . # ./leaderboard.bash Starting the CARLA evaluation script. This may take some time. Sit tight! Traceback (most recent call last): ... ModuleNotFoundError: No module named 'agent' . Solution: Ensure that there isn’t a typo in the --agent flag to leaderboard_evaluator.py. As of writing, this is in leaderboard.bash. “The RMW implementation has been specified as…” . As of 11 Nov ‘22 . CMake Error at /opt/ros/foxy/share/rmw_implementation/cmake/rmw_implementation-extras.cmake:54 (message): The RMW implementation has been specified as 'rmw_cyclonedds_cpp' via environment variable 'RMW_IMPLEMENTATION', but it is not available at this time. Currently available middlewares: 'rmw_fastrtps_cpp' . Solution . Navigator uses a slightly modified ROS Middleware (RMW) implementation called CycloneDDS. In order for ROS and its nodes to use it, our custom version must be built and sourced, just like any other ROS workspace. Docker includes the CycloneDDS workspace under /opt/cyclone_ws, and this workspace should be sourced automatically as part of the Docker entrypoint.sh. If you receive the above error, CycloneDDS was either not properly built or sourced. You can verify that the CycloneDDS is loaded properly using the command # ros2 doctor --report, which should show: ... processor : x86_64 RMW MIDDLEWARE middleware name : rmw_cyclonedds_cpp ... ", "url": "/navigator/contributing/troubleshooting.html#table-of-contents", "relUrl": "/contributing/troubleshooting.html#table-of-contents" - },"76": { + },"90": { "doc": "Writing documentation", "title": "System overview", "content": " ", "url": "/navigator/writing-documentation.html#system-overview", "relUrl": "/writing-documentation.html#system-overview" - },"77": { + },"91": { "doc": "Writing documentation", "title": "Table of contents", "content": ". | Testing locally | Editing online | . This documentation site is built off of Navigator’s dev branch. All files within the /doc directory are remapped to nova-utd.github.io. Adding to the site is easy. Here are two good options: . ", "url": "/navigator/writing-documentation.html#table-of-contents", "relUrl": "/writing-documentation.html#table-of-contents" - },"78": { + },"92": { "doc": "Writing documentation", "title": "Testing locally", "content": "To test locally, cd into /docs and run . docker run --rm --volume=\"$PWD:/srv/jekyll:Z\" -p 8083:8083 jekyll/jekyll jekyll serve --port 8083 . Use a browser to view localhost:8083. Refresh the page to show the latest updates. See the official Docker README for more info. ", "url": "/navigator/writing-documentation.html#testing-locally", "relUrl": "/writing-documentation.html#testing-locally" - },"79": { + },"93": { "doc": "Writing documentation", "title": "Editing online", "content": "On GitHub, move to the /docs directory on the dev branch (here), then press the period key on your keyboard. This will open GitHub’s web editor. See here for more info. ", "url": "/navigator/writing-documentation.html#editing-online", "relUrl": "/writing-documentation.html#editing-online" - },"80": { + },"94": { "doc": "Writing documentation", "title": "Writing documentation", "content": " ", diff --git a/docs/_site/assets/res/cost_map_size.jpg b/docs/_site/assets/res/cost_map_size.jpg new file mode 100644 index 000000000..b97c489c8 Binary files /dev/null and b/docs/_site/assets/res/cost_map_size.jpg differ diff --git a/docs/_site/assets/res/cost_maps.png b/docs/_site/assets/res/cost_maps.png new file mode 100644 index 000000000..f5a1f0cec Binary files /dev/null and b/docs/_site/assets/res/cost_maps.png differ diff --git a/docs/_site/contributing/contributing-overview.html b/docs/_site/contributing/contributing-overview.html index 9415f2ae6..4229ea409 100644 --- a/docs/_site/contributing/contributing-overview.html +++ b/docs/_site/contributing/contributing-overview.html @@ -1,4 +1,4 @@ - Contributing | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Contributing overview

Maintained by Raghav Pillai

Table of contents

  1. Source Control & Git
    1. Branching & Feature Branches
  2. Documentation
    1. Headers
    2. Function & Inline Documentation
      1. Examples:
      2. C++
      3. Python
      4. C++
      5. Python
  3. READMEs
  4. Code Standards and Guidelines
  5. Styling
  6. Variable initialization
  7. Abstraction
  8. Types, typing and type hinting
  9. Constants and parameters
  10. Misc

As an open source project, Navigator is always evolving and improving. We open our arms to anyone who’d like to contribute. To help guide contributors, we’ve developed detailed Code Guidelines & Standards, as well as documentation and branching guidelines that allow us to have a consistent developer experience regardless of author. This revolves around three main philosophies:

  • Inherent Readability
  • Consistency
  • Maintainability

By following these guidelines, we can fulfill these philosophies, which allow us to have the most efficient developer experience possible, along with having a mature and maintainable codebase.

Source Control & Git

  • Use the branching strategy described below. Do not commit directly to the main or dev branch. This applies even to simple changes, like fixing a typo!
  • Don’t merge your own pull requests to main, dev or release branches. Get the software architect or team lead to review your change and merge it.
  • Commit as often or as infrequently as you like. As long as you’re working in a branch (as described below), you can commit even a completely broken change without affecting others.

Branching & Feature Branches

We will maintain both a main branch and a dev branch. main is more stable than dev. When you begin work on a feature or a bugfix, fork the dev branch, implement your change, and create a pull request back to dev once the change is relatively stable and well tested.

Start branch names with ‘feature_’, but other than that, name them however you want. Make the name descriptive and helpful. Don’t name a branch feature_zcc - that name is not helpful to someone trying to understand what the branch is for. However, feature_zed_camera_color clearly describes what the branch is for.

Make sure your commits are meaningful and grouped up. Don’t commit your entire change history into a single commit, group them up so you have a timeline of your progress.

When we are preparing for a release, we will create a branch off of dev to test and and add bugfixes. This release will start with release_ and end with a version number - for example, release_1_0. This allows us to continue merging features into dev while a release is being worked on. Once testing is complete, the release branch will be merged into both main and dev, so that the fixes applied during testing are applied everywhere. The commit in main will be tagged as our new release.

Documentation

A cornerstone of good code is maintainability, which relies on understandable documentation. Navigator uses Doxygen to automatically generate high-level documentation from our user-defined documentation. Further documentation on how this works can be found below:

https://doxygen.nl/manual/docblocks.html

You can also use the VSCode Doxygen Generator to automatically generate proper documentation templates.

Below are the different types of documentation that are required for new contributions for Navigator.

Headers

Each file should have documentation on what the file accomplishes, as well as basic usage information. Below is our sample header comment template.

/*
+          Contributing | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Contributing overview

Maintained by Raghav Pillai

Table of contents

  1. Source Control & Git
    1. Branching & Feature Branches
  2. Documentation
    1. Headers
    2. Function & Inline Documentation
      1. Examples:
      2. C++
      3. Python
      4. C++
      5. Python
  3. READMEs
  4. Code Standards and Guidelines
  5. Styling
  6. Variable initialization
  7. Abstraction
  8. Types, typing and type hinting
  9. Constants and parameters
  10. Misc

As an open source project, Navigator is always evolving and improving. We open our arms to anyone who’d like to contribute. To help guide contributors, we’ve developed detailed Code Guidelines & Standards, as well as documentation and branching guidelines that allow us to have a consistent developer experience regardless of author. This revolves around three main philosophies:

  • Inherent Readability
  • Consistency
  • Maintainability

By following these guidelines, we can fulfill these philosophies, which allow us to have the most efficient developer experience possible, along with having a mature and maintainable codebase.

Source Control & Git

  • Use the branching strategy described below. Do not commit directly to the main or dev branch. This applies even to simple changes, like fixing a typo!
  • Don’t merge your own pull requests to main, dev or release branches. Get the software architect or team lead to review your change and merge it.
  • Commit as often or as infrequently as you like. As long as you’re working in a branch (as described below), you can commit even a completely broken change without affecting others.

Branching & Feature Branches

We will maintain both a main branch and a dev branch. main is more stable than dev. When you begin work on a feature or a bugfix, fork the dev branch, implement your change, and create a pull request back to dev once the change is relatively stable and well tested.

Start branch names with ‘feature_’, but other than that, name them however you want. Make the name descriptive and helpful. Don’t name a branch feature_zcc - that name is not helpful to someone trying to understand what the branch is for. However, feature_zed_camera_color clearly describes what the branch is for.

Make sure your commits are meaningful and grouped up. Don’t commit your entire change history into a single commit, group them up so you have a timeline of your progress.

When we are preparing for a release, we will create a branch off of dev to test and and add bugfixes. This release will start with release_ and end with a version number - for example, release_1_0. This allows us to continue merging features into dev while a release is being worked on. Once testing is complete, the release branch will be merged into both main and dev, so that the fixes applied during testing are applied everywhere. The commit in main will be tagged as our new release.

Documentation

A cornerstone of good code is maintainability, which relies on understandable documentation. Navigator uses Doxygen to automatically generate high-level documentation from our user-defined documentation. Further documentation on how this works can be found below:

https://doxygen.nl/manual/docblocks.html

You can also use the VSCode Doxygen Generator to automatically generate proper documentation templates.

Below are the different types of documentation that are required for new contributions for Navigator.

Headers

Each file should have documentation on what the file accomplishes, as well as basic usage information. Below is our sample header comment template.

/*
 * Package:   package_name
 * Filename:  FileName.cpp
 * Author:    John Doe
diff --git a/docs/_site/contributing/troubleshooting.html b/docs/_site/contributing/troubleshooting.html
index 285cf5df9..5a743b4bf 100644
--- a/docs/_site/contributing/troubleshooting.html
+++ b/docs/_site/contributing/troubleshooting.html
@@ -1,4 +1,4 @@
-          Troubleshooting | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Troubleshooting

Maintained by Nova members

Table of contents

  1. “New publisher discovered on this topic, offering incompatible QoS”
    1. Solution
  2. “RuntimeError: trying to create rpc server for traffic manager…”
  3. When running the leaderboard evaluator: “No module named ‘agent’”
    1. Solution: Ensure that there isn’t a typo in the --agent flag to leaderboard_evaluator.py. As of writing, this is in leaderboard.bash.
  4. “The RMW implementation has been specified as…”
    1. Solution

“New publisher discovered on this topic, offering incompatible QoS”

[WARN] [1669075701.737584987] [leaderboard_node]: New publisher discovered on this topic, offering incompatible QoS. No messages will be received from it. Last incompatible policy: DURABILITY_QOS_POLICY
+          Troubleshooting | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Troubleshooting

Maintained by Nova members

Table of contents

  1. “New publisher discovered on this topic, offering incompatible QoS”
    1. Solution
  2. “RuntimeError: trying to create rpc server for traffic manager…”
  3. When running the leaderboard evaluator: “No module named ‘agent’”
    1. Solution: Ensure that there isn’t a typo in the --agent flag to leaderboard_evaluator.py. As of writing, this is in leaderboard.bash.
  4. “The RMW implementation has been specified as…”
    1. Solution

“New publisher discovered on this topic, offering incompatible QoS”

[WARN] [1669075701.737584987] [leaderboard_node]: New publisher discovered on this topic, offering incompatible QoS. No messages will be received from it. Last incompatible policy: DURABILITY_QOS_POLICY
 

A warning similar to the above example will appear when a publisher and subscriber attempt to exchange messages with incompatible quality of service QoS policies.

Solution

Edit the QoS policy of either the relevant publisher or subscriber so that the two can “speak” to each other.

For more information on QoS in ROS2, including compatibility between policies, see here.

“RuntimeError: trying to create rpc server for traffic manager…”

...
   File "/workspace/leaderboard/leaderboard/leaderboard_evaluator.py", line 83, in __init__
     self.traffic_manager = self.client.get_trafficmanager(args.traffic_manager_port)
diff --git a/docs/_site/controls/controls-overview.html b/docs/_site/controls/controls-overview.html
index 7ee22584a..c13d7579c 100755
--- a/docs/_site/controls/controls-overview.html
+++ b/docs/_site/controls/controls-overview.html
@@ -1 +1 @@
-          Controls | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Controls overview

Maintained by Egan Johnson

Table of contents

  1. Sources of error
  2. Current controllers

The Controls system takes our vehicle’s current state and our target trajectory as inputs. Based on the difference between our current state and this desired trajectory, the system calculates the ideal:

  • Steering angle
  • Brake position
  • Throttle position

To make our system platform-agnostic, the Controller’s outputs are between (-1.0, 1.0) for steering and (0.0, 1.0) for throttle and brake positions. The Interface system is responsible for scaling these values to a specific platform.

Sources of error

The vehicle does not move perfectly. Physical error is introduced. There will always be errors in our model– that is, our set of assumptions about the vehicle’s physical properties and behavior.

Most importantly, there’s error in our current state, one of the inputs to our controller. In order for our controller to follow the desired trajectory, it must have an accurate understanding of where the car currently is, how fast it’s going, and which way it’s facing.

Current controllers

Our “unified controller” generates the desired steering angle and pedal positions within the same node. However, steering and pedal positions are calculated using two different controllers.

As of Sept. 21, 2022, our steering controller uses Pure Pursuit, while our throttle and brake are calculated using a simple PID controller. This combination works suitably at low speeds, though something more sophisticated like MPC would be necissary for highway driving.

+ Controls | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Controls overview

Maintained by Egan Johnson

Table of contents

  1. Sources of error
  2. Current controllers

The Controls system takes our vehicle’s current state and our target trajectory as inputs. Based on the difference between our current state and this desired trajectory, the system calculates the ideal:

  • Steering angle
  • Brake position
  • Throttle position

To make our system platform-agnostic, the Controller’s outputs are between (-1.0, 1.0) for steering and (0.0, 1.0) for throttle and brake positions. The Interface system is responsible for scaling these values to a specific platform.

Sources of error

The vehicle does not move perfectly. Physical error is introduced. There will always be errors in our model– that is, our set of assumptions about the vehicle’s physical properties and behavior.

Most importantly, there’s error in our current state, one of the inputs to our controller. In order for our controller to follow the desired trajectory, it must have an accurate understanding of where the car currently is, how fast it’s going, and which way it’s facing.

Current controllers

Our “unified controller” generates the desired steering angle and pedal positions within the same node. However, steering and pedal positions are calculated using two different controllers.

As of Sept. 21, 2022, our steering controller uses Pure Pursuit, while our throttle and brake are calculated using a simple PID controller. This combination works suitably at low speeds, though something more sophisticated like MPC would be necissary for highway driving.

diff --git a/docs/_site/feed.xml b/docs/_site/feed.xml index 2c00552c6..c013ccaff 100755 --- a/docs/_site/feed.xml +++ b/docs/_site/feed.xml @@ -1,4 +1,4 @@ -Jekyll2023-01-16T15:53:26-06:00http://0.0.0.0:8083/navigator/feed.xmlNavigatorNavigator is an open-source autonomous driving system developed by Nova, an applied research group at UT Dallas.Welcome to Jekyll!2022-09-05T21:27:33-05:002022-09-05T21:27:33-05:00http://0.0.0.0:8083/navigator/jekyll/update/2022/09/05/welcome-to-jekyll<p>You’ll find this post in your <code class="language-plaintext highlighter-rouge">_posts</code> directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run <code class="language-plaintext highlighter-rouge">jekyll serve</code>, which launches a web server and auto-regenerates your site when a file is updated.</p> +Jekyll2023-02-15T12:40:13-06:00http://0.0.0.0:8083/navigator/feed.xmlNavigatorNavigator is an open-source autonomous driving system developed by Nova, an applied research group at UT Dallas.Welcome to Jekyll!2022-09-05T21:27:33-05:002022-09-05T21:27:33-05:00http://0.0.0.0:8083/navigator/jekyll/update/2022/09/05/welcome-to-jekyll<p>You’ll find this post in your <code class="language-plaintext highlighter-rouge">_posts</code> directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run <code class="language-plaintext highlighter-rouge">jekyll serve</code>, which launches a web server and auto-regenerates your site when a file is updated.</p> <p>Jekyll requires blog post files to be named according to the following format:</p> diff --git a/docs/_site/index.html b/docs/_site/index.html index 3e02b3ac6..ba8aadc9a 100755 --- a/docs/_site/index.html +++ b/docs/_site/index.html @@ -1,4 +1,4 @@ - Navigator | Navigator is an open-source autonomous driving system developed by Nova, an applied research group at UT Dallas. Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Navigator is a simple, extensible, and open-source autonomous driving framework.

System overview View it on GitHub

Why Navigator?

Despite major advances in autonomous driving research, there has yet to exist a single framework that is both simple and extensible, all while being public and transparent.

Navigator is our answer to this delimma. It’s built on standard technologies, is kept as simple as possible, and its modular design makes adding new features straightforward.

System requirements

  • System running Ubuntu 20.04 LTS or similar (see here)
    • Docker engine already installed on Ubuntu
  • Ros2 Foxy
  • CARLA 0.9.13
  • A dedicated GPU with at least 6 GB of memory, ideally 8 GB
  • x86_64 CPU
  • About 20 GB of disk space

Installation

Note: Lines with “$” are on host, while lines with “#” are within the container.

  1. Install ROS2 Foxy if you haven’t already done so
  2. Install Docker if you haven’t already done so
  3. Clone our repository
    $ git clone --recursive https://github.com/Nova-UTD/navigator
    +          Navigator | Navigator is an open-source autonomous driving system developed by Nova, an applied research group at UT Dallas.                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

    Navigator is a simple, extensible, and open-source autonomous driving framework.

    System overview View it on GitHub

    Why Navigator?

    Despite major advances in autonomous driving research, there has yet to exist a single framework that is both simple and extensible, all while being public and transparent.

    Navigator is our answer to this delimma. It’s built on standard technologies, is kept as simple as possible, and its modular design makes adding new features straightforward.

    System requirements

    • Docker
    • CARLA 0.9.13 for simulated testing (optional)
    • For best results, a dedicated GPU with at least 6 GB of memory, ideally 8 GB
    • x86_64 CPU
    • About 20 GB of disk space

    Installation

    Note: Lines with “$” are on host, while lines with “#” are within the container.

    1. Install Docker if you haven’t already done so
    2. If not already set, choose a number between 0-100 and use this for your user-wide ROS_DOMAIN_ID. Add this to your .bashrc with echo 'export ROS_DOMAIN_ID=[your number]' >> ~/.bashrc
    3. Clone our repository
      $ git clone --recursive https://github.com/Nova-UTD/navigator
       $ cd navigator
       
    4. Build and start our Docker container
      $ docker build . -t navigator
       $ ./docker.sh
      @@ -22,7 +22,7 @@
       

    That’s it!

    CARLA demo

    1. Make sure you’ve installed Navigator using the steps above.
    2. On the host, start CARLA: ./CarlaUE4.sh See the CARLA docs for more info.

    3. Run the following commands to start our system and connect it to CARLA:
      $ ./docker.sh
       ...
       root@yourhost:/navigator# ./navigator
      -root@yourhost:/navigator# ros2 launch carla_interface carla-lite.launch.py
      +root@yourhost:/navigator# ros2 launch carla_interface carla.launch.py
       

      This should start a series of ROS nodes, spawning an ego vehicle in the simulator along with a number of sensors:

      [INFO] [launch]: All log files can be found below /root/.ros/log/2022-11-05-01-09-18-915839-justingpu-55
       [INFO] [launch]: Default logging verbosity is set to INFO
       [WARNING] [launch_ros.actions.node]: Parameter file path is not a file: /navigator/param/planning/motion_planner.param.yaml
      diff --git a/docs/_site/interface/interface-overview.html b/docs/_site/interface/interface-overview.html
      index f3d2cc120..4d4cb6a59 100644
      --- a/docs/_site/interface/interface-overview.html
      +++ b/docs/_site/interface/interface-overview.html
      @@ -1 +1 @@
      -          Interface | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

      Interface overview

      Table of contents

      1. About Hail Bopp
      2. Electrical overview

      The Interface subsystem represents the only code that is vehicle-specific by necessity. It is the link between software and hardware. Since your hardware is probably different than ours, then you’ll likely have to modify our interface code to suit your needs.

      The exception is our CARLA bridge, a simple script that spawns an ego vehicle and connects its sensors and actuators to ROS.

      In this overview, we’ll go over our hardware platform, Hail Bopp.

      About Hail Bopp

      Hail Bopp includes an Electronic Power Assisted Steering (EPAS) system, which is a motor on our steering column that allows us to apply steering force programatically.

      Our vehicle also has front and rear Velodyne Puck (VLP-16) LiDAR sensors. These generate rich, precise 3D scans of our surroundings using 16 channels of spinning lasers.

      Our platform uses ZED stereo cameras to gather color images and their corresponding depth information. Stereo cams can give us limited 3D information, but they are best used in conjuction with more accurate LiDAR data.

      We currently use an NVIDIA Jetson AGX Xavier for our onboard computing. This is likely to change soon, as we have exceeded the power capabilities of this device.

      Finally, an Adafruit Metro Grand Central serves as our real-time microcontroller. This device handles time-critical services, such as releasing our steering wheel if our high-level software fails.

      Electrical overview

      Voltron Secondary System schematic

      + Interface | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Interface overview

      Table of contents

      1. About Hail Bopp
      2. Electrical overview

      The Interface subsystem represents the only code that is vehicle-specific by necessity. It is the link between software and hardware. Since your hardware is probably different than ours, then you’ll likely have to modify our interface code to suit your needs.

      The exception is our CARLA bridge, a simple script that spawns an ego vehicle and connects its sensors and actuators to ROS.

      In this overview, we’ll go over our hardware platform, Hail Bopp.

      About Hail Bopp

      Hail Bopp includes an Electronic Power Assisted Steering (EPAS) system, which is a motor on our steering column that allows us to apply steering force programatically.

      Our vehicle also has front and rear Velodyne Puck (VLP-16) LiDAR sensors. These generate rich, precise 3D scans of our surroundings using 16 channels of spinning lasers.

      Our platform uses ZED stereo cameras to gather color images and their corresponding depth information. Stereo cams can give us limited 3D information, but they are best used in conjuction with more accurate LiDAR data.

      We currently use an NVIDIA Jetson AGX Xavier for our onboard computing. This is likely to change soon, as we have exceeded the power capabilities of this device.

      Finally, an Adafruit Metro Grand Central serves as our real-time microcontroller. This device handles time-critical services, such as releasing our steering wheel if our high-level software fails.

      Electrical overview

      Voltron Secondary System schematic

      diff --git a/docs/_site/interface/schematics.html b/docs/_site/interface/schematics.html index 5b20a7096..4d62640fe 100644 --- a/docs/_site/interface/schematics.html +++ b/docs/_site/interface/schematics.html @@ -1 +1 @@ - Schematics | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Schematics

      Main Nova Schematic

      Nova Schematic


      Power Source Schematics

      Power Source Schematics


      USB Hub Schematics

      USB Hub Schematics


      Adafruit Grand Central Schematics

      Adafruit Grand Central Schematics


      CAN Bus Systems

      CAN Bus Systems


      EPAS

      EPAS

      + Schematics | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Schematics

      Main Nova Schematic

      Nova Schematic


      Power Source Schematics

      Power Source Schematics


      USB Hub Schematics

      USB Hub Schematics


      Adafruit Grand Central Schematics

      Adafruit Grand Central Schematics


      CAN Bus Systems

      CAN Bus Systems


      EPAS

      EPAS

      diff --git a/docs/_site/jekyll/update/2022/09/05/welcome-to-jekyll.html b/docs/_site/jekyll/update/2022/09/05/welcome-to-jekyll.html index 5f877d88e..96f9d3450 100755 --- a/docs/_site/jekyll/update/2022/09/05/welcome-to-jekyll.html +++ b/docs/_site/jekyll/update/2022/09/05/welcome-to-jekyll.html @@ -1,4 +1,4 @@ - Welcome to Jekyll! | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.

      Jekyll requires blog post files to be named according to the following format:

      YEAR-MONTH-DAY-title.MARKUP

      Where YEAR is a four-digit number, MONTH and DAY are both two-digit numbers, and MARKUP is the file extension representing the format used in the file. After that, include the necessary front matter. Take a look at the source for this post to get an idea about how it works.

      Jekyll also offers powerful support for code snippets:

      def print_hi(name)
      +          Welcome to Jekyll! | Navigator                  Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

      You’ll find this post in your _posts directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run jekyll serve, which launches a web server and auto-regenerates your site when a file is updated.

      Jekyll requires blog post files to be named according to the following format:

      YEAR-MONTH-DAY-title.MARKUP

      Where YEAR is a four-digit number, MONTH and DAY are both two-digit numbers, and MARKUP is the file extension representing the format used in the file. After that, include the necessary front matter. Take a look at the source for this post to get an idea about how it works.

      Jekyll also offers powerful support for code snippets:

      def print_hi(name)
         puts "Hi, #{name}"
       end
       print_hi('Tom')
      diff --git a/docs/_site/opendrivepy.html b/docs/_site/opendrivepy.html
      index ac80eadd4..9c8e01491 100644
      --- a/docs/_site/opendrivepy.html
      +++ b/docs/_site/opendrivepy.html
      @@ -1,4 +1,4 @@
      -          OpenDrivePy | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

      OpenDrivePy

      Maintained by Will Heitman

      Table of contents

      1. TOC

      Element tree

      Map
      +          OpenDrivePy | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

      OpenDrivePy

      Maintained by Will Heitman

      Table of contents

      1. TOC

      Element tree

      Map
       ├── get_route(): Lane[]
       ├── header: Header (contains north, x0, and other geo ref data)
       ├── shapes: STRTree
      diff --git a/docs/_site/perception/mapping.html b/docs/_site/perception/mapping.html
      index e87b474b1..aa2934059 100644
      --- a/docs/_site/perception/mapping.html
      +++ b/docs/_site/perception/mapping.html
      @@ -1 +1 @@
      -          Localization and Mapping | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

      Localization and Mapping

      Maintained by Will Heitman

      Table of contents

      1. TOC

      Octomap Module

      Using the open-source Octomap library in conjunction with a particle filter, this module aims to provide a long-term, simultaneous localization and mapping solution.

      Target

      • Translational accuracy of $\pm 1.0$ meters at worst, $\pm 0.25$ meters nominal in urban environment.
      • Heading accuracy of $\pm 30 \degree$ at worst, $\pm 10\degree$ nominal in urban environment.
      • Above worst-case accuracy only occurs 1% of the time.
      • Able to operate in case of loss from GNSS and/or IMU.

      Behavior

      1. On start, the module should attempt to load an existing map using the map name from /carla/world_info.
        1. If no file exists, create an empty Octree and save this.
      2. When new odometry is received (such as from an IMU), store this as an accumulated offset $(\Delta x, \Delta y, \Delta \theta)$. Update the stored Odometry message and publish it with the new offset.
      3. When a new LiDAR point cloud is received, feed this into the particle filter.
        1. Update all particles using the accumulated offset and Gaussian noise in a motion update.
        2. Evaluate the probability of each particle in an observation update.
        3. Resample all particles using their probabilities.
        4. Compute a new robot pose using the mean and covariance of the particles.
        5. Publish the pose as an Odometry message.
      4. After the pose is updated from the LiDAR cloud, this cloud should be added to the map.
      5. Steps 2-4 should be repeated in a loop.
      6. A timer should prompt a visualization_msgs/Marker to be published periodically that visualizes the voxel map.
      7. Upon termination, the octree map should be saved to a file using the name from (1).

      Progressive resolution of visualization

      Progressive map visualization

      Assumptions

      • The robot will only move along a 2D plane. That is, only 3-DOF motion will be assumed, and the localization will be calculated accordingly.
      + Localization and Mapping | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Localization and Mapping

      Maintained by Will Heitman

      Table of contents

      1. TOC

      Octomap Module

      Using the open-source Octomap library in conjunction with a particle filter, this module aims to provide a long-term, simultaneous localization and mapping solution.

      Target

      • Translational accuracy of $\pm 1.0$ meters at worst, $\pm 0.25$ meters nominal in urban environment.
      • Heading accuracy of $\pm 30 \degree$ at worst, $\pm 10\degree$ nominal in urban environment.
      • Above worst-case accuracy only occurs 1% of the time.
      • Able to operate in case of loss from GNSS and/or IMU.

      Behavior

      1. On start, the module should attempt to load an existing map using the map name from /carla/world_info.
        1. If no file exists, create an empty Octree and save this.
      2. When new odometry is received (such as from an IMU), store this as an accumulated offset $(\Delta x, \Delta y, \Delta \theta)$. Update the stored Odometry message and publish it with the new offset.
      3. When a new LiDAR point cloud is received, feed this into the particle filter.
        1. Update all particles using the accumulated offset and Gaussian noise in a motion update.
        2. Evaluate the probability of each particle in an observation update.
        3. Resample all particles using their probabilities.
        4. Compute a new robot pose using the mean and covariance of the particles.
        5. Publish the pose as an Odometry message.
      4. After the pose is updated from the LiDAR cloud, this cloud should be added to the map.
      5. Steps 2-4 should be repeated in a loop.
      6. A timer should prompt a visualization_msgs/Marker to be published periodically that visualizes the voxel map.
      7. Upon termination, the octree map should be saved to a file using the name from (1).

      Progressive resolution of visualization

      Progressive map visualization

      Assumptions

      • The robot will only move along a 2D plane. That is, only 3-DOF motion will be assumed, and the localization will be calculated accordingly.
      diff --git a/docs/_site/perception/perception-overview.html b/docs/_site/perception/perception-overview.html index 28c73a0f8..16c61c27c 100755 --- a/docs/_site/perception/perception-overview.html +++ b/docs/_site/perception/perception-overview.html @@ -1 +1 @@ - Perception | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Perception overview

      Maintained by Ragib Arnab

      Table of contents

      1. darknet_inference
      2. obstacle_detection_3d
      3. obstacle_classes
      4. obstacle_drawer
      5. lidar_fusion
      6. lidar_obstacle_detector

      The perception component of the system takes the data from various sensors and extracts meaningful information for downstream components such as planning.

      Some of the tasks that are core parts of the perception include, but not limited to:

      • Localization and state estimation
      • Obstacle and scene classifiation
      • Obstacle tracking and prediction

      In this page we will go each individual packages that is part of the perception component. A lot of the packages within perception are “in-progress” just as with most other packages within our system. As this project progresses, we will update the existing packages as well as add new ones to meet the growing demands of our autonomous system.

      darknet_inference

      The darknet_inference package contains Python tools to build and run Darknet-based object detection models in ROS 2. The standard model that is used is YOLOv4 which can achieve real-time inference on a modern GPU with good overall accuracy. There is also an option to use the YOLOv4-tiny model to increase the inference rate but with a sacrifice to accuracy. The node for this package subscribes to a RGB image message topic and outputs 2D bounding box predictions for each class of object in its own message formats. In this current version of navigator, all the detections for the vehicle is performed in this node, which includes detecting cars and pedestrians as well as finding landmarks such as stop signs and fire hydrants. All these detections are also processed within the node itself by using parameters such as object confidence threshold and non-maximum suppression (NMS) threshold to filter out the unwanted detections.

      obstacle_detection_3d

      This package takes as input the 2D detections along with 3D sensing data from lidars and depth camera to output 3D bounding boxes. 3D detection are required for behavior and planning components of our system. Currently the code simply backprojects the 2D bounding boxes into 3D using information and extends the boxes into a cuboid based on the object’s class. This is a naive approach given that the orientation information of the cuboids will be the same as the vehicle and that the lengths of the objects are fixed. The algorithm is a placeholder and will be replaced by an actual 3-D object detection algorithm in the future.

      obstacle_classes

      Contains the enumeration definition for the different classes of obstacles.

      obstacle_drawer

      A simple visualization package that takes the 3D bounding box outputs and produces visualization messages that can be depicted in RViz.

      lidar_fusion

      This package fuses the 2 different lidar sources within our system into a single point cloud that will be registered into the same frame (base-link) within the system transform tree. The package also performs basic point cloud filtering.

      lidar_obstacle_detector

      This package is tasked with detecting low-level obstacles around the vehicle for the purpose of collision prevention. The node takes as input a point cloud and output zones around the vehicle for low-level obstacles.

      + Perception | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Perception overview

      Maintained by Ragib Arnab

      Table of contents

      1. darknet_inference
      2. obstacle_detection_3d
      3. obstacle_classes
      4. obstacle_drawer
      5. lidar_fusion
      6. lidar_obstacle_detector

      The perception component of the system takes the data from various sensors and extracts meaningful information for downstream components such as planning.

      Some of the tasks that are core parts of the perception include, but not limited to:

      • Localization and state estimation
      • Obstacle and scene classifiation
      • Obstacle tracking and prediction

      In this page we will go each individual packages that is part of the perception component. A lot of the packages within perception are “in-progress” just as with most other packages within our system. As this project progresses, we will update the existing packages as well as add new ones to meet the growing demands of our autonomous system.

      darknet_inference

      The darknet_inference package contains Python tools to build and run Darknet-based object detection models in ROS 2. The standard model that is used is YOLOv4 which can achieve real-time inference on a modern GPU with good overall accuracy. There is also an option to use the YOLOv4-tiny model to increase the inference rate but with a sacrifice to accuracy. The node for this package subscribes to a RGB image message topic and outputs 2D bounding box predictions for each class of object in its own message formats. In this current version of navigator, all the detections for the vehicle is performed in this node, which includes detecting cars and pedestrians as well as finding landmarks such as stop signs and fire hydrants. All these detections are also processed within the node itself by using parameters such as object confidence threshold and non-maximum suppression (NMS) threshold to filter out the unwanted detections.

      obstacle_detection_3d

      This package takes as input the 2D detections along with 3D sensing data from lidars and depth camera to output 3D bounding boxes. 3D detection are required for behavior and planning components of our system. Currently the code simply backprojects the 2D bounding boxes into 3D using information and extends the boxes into a cuboid based on the object’s class. This is a naive approach given that the orientation information of the cuboids will be the same as the vehicle and that the lengths of the objects are fixed. The algorithm is a placeholder and will be replaced by an actual 3-D object detection algorithm in the future.

      obstacle_classes

      Contains the enumeration definition for the different classes of obstacles.

      obstacle_drawer

      A simple visualization package that takes the 3D bounding box outputs and produces visualization messages that can be depicted in RViz.

      lidar_fusion

      This package fuses the 2 different lidar sources within our system into a single point cloud that will be registered into the same frame (base-link) within the system transform tree. The package also performs basic point cloud filtering.

      lidar_obstacle_detector

      This package is tasked with detecting low-level obstacles around the vehicle for the purpose of collision prevention. The node takes as input a point cloud and output zones around the vehicle for low-level obstacles.

      diff --git a/docs/_site/perception/perception_new.html b/docs/_site/perception/perception_new.html index 819a2e9b7..a468f8df2 100644 --- a/docs/_site/perception/perception_new.html +++ b/docs/_site/perception/perception_new.html @@ -1,4 +1,4 @@ - Perception and Prediction Design Document (draft) | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Perception and Prediction Design Document (draft)

      Maintained by Ashwin

      Table of contents

      1. System Overview
        1. Current System:
          1. Prediction:
        2. Planned System:
          1. Perception:
          2. Prediction:
        3. Proposed structures for Phase 1:
          1. 3D/2D bounding boxes:
          2. System overview for Dynamic Environment Prediction
          3. Proposed structure for Dynamic Environment Prediction

      System Overview

      Current System:

      Prediction:

      - Zones in place of dynamic object detection 
      +          Perception and Prediction Design Document (draft) | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

      Perception and Prediction Design Document (draft)

      Maintained by Ashwin

      Table of contents

      1. System Overview
        1. Current System:
          1. Prediction:
        2. Planned System:
          1. Perception:
          2. Prediction:
        3. Proposed structures for Phase 1:
          1. 3D/2D bounding boxes:
          2. System overview for Dynamic Environment Prediction
          3. Proposed structure for Dynamic Environment Prediction

      System Overview

      Current System:

      Prediction:

      - Zones in place of dynamic object detection 
       
       - Acts as a safety net cast over objects in view of the vehicle 
       
      diff --git a/docs/_site/planning/design.html b/docs/_site/planning/design.html
      index d6529da26..d0421b4b4 100644
      --- a/docs/_site/planning/design.html
      +++ b/docs/_site/planning/design.html
      @@ -1 +1 @@
      -          Behavior Planning and Controls Design Document (draft) | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

      Behavior Planning and Controls Design Document (draft)

      Maintained by Hansika

      Table of contents

      1. Important Definitions Used in Doc:
      2. System overview
        1. Current system:
          1. Planning:
          2. Controls:
        2. What Planning intends to accomplish:
        3. What Planning needs:
          1. Input:
          2. Justification:
          3. Proposed Planning System:
      3. Proposed structure
        1. Current-State Information Required:
        2. Representation of Surrounding Environment:
        3. Dynamic Occupancy Grid:
          1. Structure of Grid:
          2. Information within cell:
        4. Conversion to Cost Map:
          1. Determination of Cost:
          2. Distance From End:
          3. Number of merges/turns:
            1. Good traffic navigation protocols:
          4. Calculation of Path Costs:

      Important Definitions Used in Doc:

      Configuration Space: set of all configurations of a vehicle

      System overview

      Current system:

      Planning:

      We use zones to determine speed at given way points, acting like an ‘on-rails’ vehicle. Zones are an enclosed region of space (represented as a polygon) with a maximum speed, which may be 0 to indicate a no-entry zone. Zones may overlap (in which case the lower speed wins). Zones may come from a variety of sources but currently originate from the Behavior Planner (Traffic Planner) and the Obstacle Zoner. Zones are currently not tagged with a type or origin: all zones are anonymous and equal.

      Controls:

      Uses pure pursuit for steering control. The velocity controller is best not mentioned and should be replaced.

      What Planning intends to accomplish:

      Develop a planning system that can take in a prediction about where cars, pedestrians, and other dynamic agents will be several seconds in the future and how we can find the most efficient trajectory for our autonomous vehicle (hereinafter referred to as the AV) on a short-term distance to get from point A to B (< a hundred feet) on a long-term path determined by widely spaced waypoints (> several miles).

      What Planning needs:

      Input:

      We choose to represent our prediction of the ground-truth state environment surrounding the AV several seconds in advanced using a Dynamic Occupancy Grid. This Dynamic Occupancy Grid will ideally hold information (in the form of probabilities) about whether a given grid cell (xn, yn) in a 2-Dimensional representation of real space (x, y) is occupied by an obstacle at some time tick t. This Dynamic Occupancy Grid will contain an individual grid frame (hereinafter referred to as a frame) for every discrete decisecond time tick for up to 3 seconds in advance of the current time state t = 0. Each of the frames in the Dynamic Occupancy Grid will be based on the local coordinate grid system around the AV.

      Justification:

      Because safety is the highest priority when designing a AV planning system, our primary goal is to ensure that crashes never occur when our vehicle has the ability to avoid them. For simplicity, we treat all crashes with equal importance, meaning crashing with an animal, pedestrian, or other vehicles are all given equal “badness”. Defining a crash as the collision between the bounding boxes of two objects within real space, the only information we need to know is when another object’s bounding box will collide with our own. Knowing this, we can track all possible collisions with other dynamic and static objects through creating a Dynamic Occupancy Grid that tells us the spaces that contain other objects at some time t, for which we should not also occupy at that time t. The usefulness of the Dynamic Occupancy Grid is that all agents within our environment can be easily represented under the Grid because they all can be easily and efficiently sampled for any (x, y, t), whereas Zones struggled with efficiency and was unable to represent time altogether.

      Proposed Planning System:

      Our proposed behavior planning and controls subsystem takes in a dynamic Occupancy Grid as the input for our planning system. Our planning system will output a path of waypoints finely spaced by equal time steps to help navigate the car to the correct location.

      In order to make this possible, we have outlined some approaches/options for planning and controls. This document outlines our proposed methods and how they fit together to form a cohesive subsystem. It describes what our system is not responsible for as well. Finally, it compares our proposed methods to Navigator’s current approach and to other popular methods in the literature.

      Proposed structure

      BPC_Flow

      Current-State Information Required:

      Position (x,y,z) Linear velocities (vx, vy, vz)

      Orientation (Theta_x, Theya_y, Theta_z) angular velocities (wx, wy, wz) (Egan: take a brief look into use of quaternions for modeling orientation and its derivatives, as that’s what currently is used)

      Short-term local coordinate transform history

      Representation of Surrounding Environment:

      Source: [1]

      BPC_options

      Voroni Diagrams: unsuitable for non-holonomic vehicles (cars)

      State lattices: repeating primitive paths which connect possible states for the vehicle [1]

      Dynamic Occupancy Grid:

      Structure of Grid:

      Each frame of the grid will be created around the local coordinate grid of the AV. It will span 40 meters to the left, 40 meters to the right, 40 meters behind, and 80 meters in front of the current position of the AV at time t = 0. Each grid cell will be made of squares spanning 0.2 meters long and wide. Each frame will represent a discrete time t = a/10 where a = (0, 30) such that our dynamic grid includes predictions from times t = (0, 3).

      The grid must be timestamped with when it was created so coordinate systems can be properly matched. The map is accessed via M[t, x,y], where higher values of x and y are to the front and right of the vehicle respectively. (The rear leftmost point is index (0,0)).

      Information within cell:

      Each cell is associated with a probability of cell being occupied by an obstacle (float value). This probability will be in the range [0, 1].

      Conversion to Cost Map:

      Determination of Cost:

      The primary factor associated with cost will be crashes. Trajectories that lead to crashes will be given extremely high costs to deter the planner from choosing them. The Dynamic Occupancy Grid can be converted into a Cost Map. Other factors to associate with cost are: Travel distance, number of merges/turns, good traffic navigation protocols, etc. We would also use the measure of traffic in different lanes to help us determine cost of a given path.

      Distance From End:

      Each path should be assigned a cost value proportional to the maximum distance from its final position of the AV and the next waypoint.

      (Egan: I’m confused about this one. The point is that we maximize travel distance in the direction we want to go, and costs are relative to other paths, so consant cost increase don’t matter.) (Response – Chitsein: I think I was thinking incorrectly about travel distance’s relevance to the cost map – I meant for it to originally represent the travel distance between two points a and b. I realize that the RRT won’t be creating paths to get from a point a to b, but will rather find all paths that could be taken by the AV, so I think making Travel Distance represent a cost proportional to the maximum distance like you suggested would be the better design. )

      Number of merges/turns:

      Increasing the cost of a path every time the AV merges or makes a turn to deter from paths that make unneccessary merges or turns. For example, we probably don’t want the vehicle to be merging in and out of lanes constantly on the highway to move a little faster at the expense of slowing down others cars it merges in front of and possibly increasing risk of collision.

      Good traffic navigation protocols:

      Increase the cost of a path that do not follow good traffic navigation protocols. For example, imagine there is a line up of cars to turn right into the highway. Based on the cost map before good traffic navigation protocols are applied, the car could choose to turn into the left lane and then try to merge at the front of the line because it would decrease the time taken to get onto the highway. However, this would go against courteous driving practices, so we should teach the AV to wait it’s turn in the line.

      Calculation of Path Costs:

      Each path’s cost is calculated based on the summation of the costs of each grid cell at time t (C[t, x, y]) plus the other factors associated with cost, including distance from end, number of merges/turns, and good traffic navigation protocols.

      Cost for travel from a given to another: Source [4]

      We can represent the points into a graph with vertices being possible options given current position and environment. Edges are the transition from a given point (where AV currently is) to next point. We weight transition to be the following equation: Source [4]

      Cost_math_method

      Proposal (Egan, I think this makes sense, I also think that we may need to tweak this conversion when we try to decide algorithms that work best for RRTs - Hansika): We may additionally want a cost function more general than a summation over occupied cells. The specific case I’m thinking of is we want to encode that, where possible, the vehicle should end in drivable area at the prediction horizon- we don’t want to attempt to overtake where since it looks good now, but when the horizon rolls forward the vehicle realizes it was impossible halfway through. This cannot be encoded by a cost map alone. So a more general approach is: C(P)=∑C_i (P), where Pis the path under consideration, C(P) is the associated cost, and C_i (P) is a component cost function. So grid cost C_g (P)=∑8t▒∑{x \〖in X〗t }▒∑{y∈Y_t }▒〖C[t,x,y]〗

      Tweaks based on the 10/13 meeting: We have two places to inject cost, which is the RRT cost function evaluated on a per-node basis and a function of the leaf nodes. • RRT cost: cost that can be evaluated at each node without knowing where it will end up ○ Cost map: occupancy grid, road semantics (drivable area) ○ Safety/Dynamic considerations: physical obtainability, difference between trajectory speed and road speed limit. A function of the state more than a lookup in the cost map. • Leaf nodes: ○ Whether the trajectory ends up in drivable area ○ Whether the trajectory ends up closer to the goal? This may be possible to push into RRT cost but makes more sense based on endpoints.

      RRTs:

      Approach 1: Algorithm for RRTs with random sampling: [1] Input requirements: Configuration Space Ouputs: best state to go to next or Xnear

      Benefits: 1. probabilistically complete a. If solution for path problem exists, RRT will find a soln with probability of 1 as running time goes to infinity 2. Guarantee kinematic feasibility 3. Quick to explore free space

      Detractions: 1. Jerky paths created 2. Strong dependence on Neares Neighbor metric 3. Need to do collision checking for every expanded node

      bpc_rrt_algo

      Approach 2: Source [3]

      RRT* - works towards shortest path

      1. Records distance each vertex has traveled relative to parent
      2. Closest node to parent vertex can be replaced by node with lower cost in given radius
      3. Neighbhors can be changed higher up in the tree if a cheaper path is found.

      Disadvantages:

      1. More computationally expensive

      Psuedo Code: Source [3]:

      bpc_rrt_algo

      Approach 3: Instead of using random point, all feasible connections are evaluated and only minimum cost paths are added to the tree.

      Given a cost map, we could build off it in the following manner:

      1. Cost functions: c_safety and c_time calculations can be found in source [4]

      To expand tree: souce [5]

      1. Sample a pposition uniformly at random and then sample two dimenssionaly gaussian distribution centered at the around intial path.

      bpc_rrt*_algo

      Approach 4: CL-RRT

      Tree expansion: grows a tree of feasible trajectories originating from the current vehicle state that attempts to reach a specified goal set [2]

      bpc_cl_rrt_algo

      Further RRT approaches are described here: https://en.wikipedia.org/wiki/Rapidly-exploring_random_tree Once we decide on a cost map approach, we can determine an algorithm to use using the cost map to create edge weights. Using heuristic algorithms such as A-star, greedy, BFS, etc. We can see if building off the avalaible methods (cost-functions, and weight functions) mentioned above into one of these algorithms, will help with making the best decision.

      Other choices than RRTs:

      Lattice Planners: We don’t wnat to use this because we are getting a dynamic grid:

      bpc_rrt_vs_lattice_planners

      Source 1: https://www.sciencedirect.com/science/article/pii/S0968090X15003447

      Source 2: https://dspace.mit.edu/bitstream/handle/1721.1/65396/Frazzoli-2009-Real-Time%20Motion%20Planning%20With%20Applications%20to%20Autonomous%20Urban%20Driving.pdf?sequence=1&isAllowed=y

      Source 3: https://theclassytim.medium.com/robotic-path-planning-rrt-and-rrt-212319121378

      Source 4: https://www.scitepress.org/Papers/2012/40334/pdf/index.html

      Source 5: https://www.researchgate.net/profile/Michael-Brunner-9/publication/236847575_Hierarchical_Rough_Terrain_Motion_Planning_using_an_Optimal_Sampling-Based_Method/links/0c9605196187ad600f000000/Hierarchical-Rough-Terrain-Motion-Planning-using-an-Optimal-Sampling-Based-Method.pdf

      Creating occupancy map: https://www.scitepress.org/Papers/2012/40334/pdf/index.html -> to share with perception team if they want

      Control:

      Current System (Severely lacking, high potential): • PurePursuit ○ Tracking algorithm enabling the vehicle’s steering wheel to smoothly adjust steering angle in relation to the curve of the given trajectory. ○ ***Possibly can breakdown this algorithm and apply similar smoothing to other aspects of our vehicle’s movement, such as velocity, acceleration, breaking.

      Input: Final, Unidisputed Trajectory: Set of discrete points, x(t), in a local coordinate system taken at time t0 Current Vehicle State Coordinate transform history between t0 and now

      Output: Commands to hardware on vehicle

      Planned System: • PurePursuit likely kept ○ Possibly expanded/using similar approaches to smoothing velocity along trajectory • Input: ○ Final, Unidisputed Trajectory: Set of discrete points (waypoints), x(t) or v(t) [Depends on RRT and how we determine cost-effective routes) • Output: ○ Precise commands to vehicle hardware ▪ Steering ▪ Pedal ▪ Break ○ Communicate with HFE team PurePursuit More PurePursuit

      + Behavior Planning and Controls Design Document (draft) | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Behavior Planning and Controls Design Document (draft)

      Maintained by Hansika

      Table of contents

      1. Important Definitions Used in Doc:
      2. System overview
        1. Current system:
          1. Planning:
          2. Controls:
        2. What Planning intends to accomplish:
        3. What Planning needs:
          1. Input:
          2. Justification:
          3. Proposed Planning System:
      3. Proposed structure
        1. Current-State Information Required:
        2. Representation of Surrounding Environment:
        3. Dynamic Occupancy Grid:
          1. Structure of Grid:
          2. Information within cell:
        4. Conversion to Cost Map:
          1. Determination of Cost:
          2. Distance From End:
          3. Number of merges/turns:
            1. Good traffic navigation protocols:
          4. Calculation of Path Costs:

      Important Definitions Used in Doc:

      Configuration Space: set of all configurations of a vehicle

      System overview

      Current system:

      Planning:

      We use zones to determine speed at given way points, acting like an ‘on-rails’ vehicle. Zones are an enclosed region of space (represented as a polygon) with a maximum speed, which may be 0 to indicate a no-entry zone. Zones may overlap (in which case the lower speed wins). Zones may come from a variety of sources but currently originate from the Behavior Planner (Traffic Planner) and the Obstacle Zoner. Zones are currently not tagged with a type or origin: all zones are anonymous and equal.

      Controls:

      Uses pure pursuit for steering control. The velocity controller is best not mentioned and should be replaced.

      What Planning intends to accomplish:

      Develop a planning system that can take in a prediction about where cars, pedestrians, and other dynamic agents will be several seconds in the future and how we can find the most efficient trajectory for our autonomous vehicle (hereinafter referred to as the AV) on a short-term distance to get from point A to B (< a hundred feet) on a long-term path determined by widely spaced waypoints (> several miles).

      What Planning needs:

      Input:

      We choose to represent our prediction of the ground-truth state environment surrounding the AV several seconds in advanced using a Dynamic Occupancy Grid. This Dynamic Occupancy Grid will ideally hold information (in the form of probabilities) about whether a given grid cell (xn, yn) in a 2-Dimensional representation of real space (x, y) is occupied by an obstacle at some time tick t. This Dynamic Occupancy Grid will contain an individual grid frame (hereinafter referred to as a frame) for every discrete decisecond time tick for up to 3 seconds in advance of the current time state t = 0. Each of the frames in the Dynamic Occupancy Grid will be based on the local coordinate grid system around the AV.

      Justification:

      Because safety is the highest priority when designing a AV planning system, our primary goal is to ensure that crashes never occur when our vehicle has the ability to avoid them. For simplicity, we treat all crashes with equal importance, meaning crashing with an animal, pedestrian, or other vehicles are all given equal “badness”. Defining a crash as the collision between the bounding boxes of two objects within real space, the only information we need to know is when another object’s bounding box will collide with our own. Knowing this, we can track all possible collisions with other dynamic and static objects through creating a Dynamic Occupancy Grid that tells us the spaces that contain other objects at some time t, for which we should not also occupy at that time t. The usefulness of the Dynamic Occupancy Grid is that all agents within our environment can be easily represented under the Grid because they all can be easily and efficiently sampled for any (x, y, t), whereas Zones struggled with efficiency and was unable to represent time altogether.

      Proposed Planning System:

      Our proposed behavior planning and controls subsystem takes in a dynamic Occupancy Grid as the input for our planning system. Our planning system will output a path of waypoints finely spaced by equal time steps to help navigate the car to the correct location.

      In order to make this possible, we have outlined some approaches/options for planning and controls. This document outlines our proposed methods and how they fit together to form a cohesive subsystem. It describes what our system is not responsible for as well. Finally, it compares our proposed methods to Navigator’s current approach and to other popular methods in the literature.

      Proposed structure

      BPC_Flow

      Current-State Information Required:

      Position (x,y,z) Linear velocities (vx, vy, vz)

      Orientation (Theta_x, Theya_y, Theta_z) angular velocities (wx, wy, wz) (Egan: take a brief look into use of quaternions for modeling orientation and its derivatives, as that’s what currently is used)

      Short-term local coordinate transform history

      Representation of Surrounding Environment:

      Source: [1]

      BPC_options

      Voroni Diagrams: unsuitable for non-holonomic vehicles (cars)

      State lattices: repeating primitive paths which connect possible states for the vehicle [1]

      Dynamic Occupancy Grid:

      Structure of Grid:

      Each frame of the grid will be created around the local coordinate grid of the AV. It will span 40 meters to the left, 40 meters to the right, 40 meters behind, and 80 meters in front of the current position of the AV at time t = 0. Each grid cell will be made of squares spanning 0.2 meters long and wide. Each frame will represent a discrete time t = a/10 where a = (0, 30) such that our dynamic grid includes predictions from times t = (0, 3).

      The grid must be timestamped with when it was created so coordinate systems can be properly matched. The map is accessed via M[t, x,y], where higher values of x and y are to the front and right of the vehicle respectively. (The rear leftmost point is index (0,0)).

      Information within cell:

      Each cell is associated with a probability of cell being occupied by an obstacle (float value). This probability will be in the range [0, 1].

      Conversion to Cost Map:

      Determination of Cost:

      The primary factor associated with cost will be crashes. Trajectories that lead to crashes will be given extremely high costs to deter the planner from choosing them. The Dynamic Occupancy Grid can be converted into a Cost Map. Other factors to associate with cost are: Travel distance, number of merges/turns, good traffic navigation protocols, etc. We would also use the measure of traffic in different lanes to help us determine cost of a given path.

      Distance From End:

      Each path should be assigned a cost value proportional to the maximum distance from its final position of the AV and the next waypoint.

      (Egan: I’m confused about this one. The point is that we maximize travel distance in the direction we want to go, and costs are relative to other paths, so consant cost increase don’t matter.) (Response – Chitsein: I think I was thinking incorrectly about travel distance’s relevance to the cost map – I meant for it to originally represent the travel distance between two points a and b. I realize that the RRT won’t be creating paths to get from a point a to b, but will rather find all paths that could be taken by the AV, so I think making Travel Distance represent a cost proportional to the maximum distance like you suggested would be the better design. )

      Number of merges/turns:

      Increasing the cost of a path every time the AV merges or makes a turn to deter from paths that make unneccessary merges or turns. For example, we probably don’t want the vehicle to be merging in and out of lanes constantly on the highway to move a little faster at the expense of slowing down others cars it merges in front of and possibly increasing risk of collision.

      Good traffic navigation protocols:

      Increase the cost of a path that do not follow good traffic navigation protocols. For example, imagine there is a line up of cars to turn right into the highway. Based on the cost map before good traffic navigation protocols are applied, the car could choose to turn into the left lane and then try to merge at the front of the line because it would decrease the time taken to get onto the highway. However, this would go against courteous driving practices, so we should teach the AV to wait it’s turn in the line.

      Calculation of Path Costs:

      Each path’s cost is calculated based on the summation of the costs of each grid cell at time t (C[t, x, y]) plus the other factors associated with cost, including distance from end, number of merges/turns, and good traffic navigation protocols.

      Cost for travel from a given to another: Source [4]

      We can represent the points into a graph with vertices being possible options given current position and environment. Edges are the transition from a given point (where AV currently is) to next point. We weight transition to be the following equation: Source [4]

      Cost_math_method

      Proposal (Egan, I think this makes sense, I also think that we may need to tweak this conversion when we try to decide algorithms that work best for RRTs - Hansika): We may additionally want a cost function more general than a summation over occupied cells. The specific case I’m thinking of is we want to encode that, where possible, the vehicle should end in drivable area at the prediction horizon- we don’t want to attempt to overtake where since it looks good now, but when the horizon rolls forward the vehicle realizes it was impossible halfway through. This cannot be encoded by a cost map alone. So a more general approach is: C(P)=∑C_i (P), where Pis the path under consideration, C(P) is the associated cost, and C_i (P) is a component cost function. So grid cost C_g (P)=∑8t▒∑{x \〖in X〗t }▒∑{y∈Y_t }▒〖C[t,x,y]〗

      Tweaks based on the 10/13 meeting: We have two places to inject cost, which is the RRT cost function evaluated on a per-node basis and a function of the leaf nodes. • RRT cost: cost that can be evaluated at each node without knowing where it will end up ○ Cost map: occupancy grid, road semantics (drivable area) ○ Safety/Dynamic considerations: physical obtainability, difference between trajectory speed and road speed limit. A function of the state more than a lookup in the cost map. • Leaf nodes: ○ Whether the trajectory ends up in drivable area ○ Whether the trajectory ends up closer to the goal? This may be possible to push into RRT cost but makes more sense based on endpoints.

      RRTs:

      Approach 1: Algorithm for RRTs with random sampling: [1] Input requirements: Configuration Space Ouputs: best state to go to next or Xnear

      Benefits: 1. probabilistically complete a. If solution for path problem exists, RRT will find a soln with probability of 1 as running time goes to infinity 2. Guarantee kinematic feasibility 3. Quick to explore free space

      Detractions: 1. Jerky paths created 2. Strong dependence on Neares Neighbor metric 3. Need to do collision checking for every expanded node

      bpc_rrt_algo

      Approach 2: Source [3]

      RRT* - works towards shortest path

      1. Records distance each vertex has traveled relative to parent
      2. Closest node to parent vertex can be replaced by node with lower cost in given radius
      3. Neighbhors can be changed higher up in the tree if a cheaper path is found.

      Disadvantages:

      1. More computationally expensive

      Psuedo Code: Source [3]:

      bpc_rrt_algo

      Approach 3: Instead of using random point, all feasible connections are evaluated and only minimum cost paths are added to the tree.

      Given a cost map, we could build off it in the following manner:

      1. Cost functions: c_safety and c_time calculations can be found in source [4]

      To expand tree: souce [5]

      1. Sample a pposition uniformly at random and then sample two dimenssionaly gaussian distribution centered at the around intial path.

      bpc_rrt*_algo

      Approach 4: CL-RRT

      Tree expansion: grows a tree of feasible trajectories originating from the current vehicle state that attempts to reach a specified goal set [2]

      bpc_cl_rrt_algo

      Further RRT approaches are described here: https://en.wikipedia.org/wiki/Rapidly-exploring_random_tree Once we decide on a cost map approach, we can determine an algorithm to use using the cost map to create edge weights. Using heuristic algorithms such as A-star, greedy, BFS, etc. We can see if building off the avalaible methods (cost-functions, and weight functions) mentioned above into one of these algorithms, will help with making the best decision.

      Other choices than RRTs:

      Lattice Planners: We don’t wnat to use this because we are getting a dynamic grid:

      bpc_rrt_vs_lattice_planners

      Source 1: https://www.sciencedirect.com/science/article/pii/S0968090X15003447

      Source 2: https://dspace.mit.edu/bitstream/handle/1721.1/65396/Frazzoli-2009-Real-Time%20Motion%20Planning%20With%20Applications%20to%20Autonomous%20Urban%20Driving.pdf?sequence=1&isAllowed=y

      Source 3: https://theclassytim.medium.com/robotic-path-planning-rrt-and-rrt-212319121378

      Source 4: https://www.scitepress.org/Papers/2012/40334/pdf/index.html

      Source 5: https://www.researchgate.net/profile/Michael-Brunner-9/publication/236847575_Hierarchical_Rough_Terrain_Motion_Planning_using_an_Optimal_Sampling-Based_Method/links/0c9605196187ad600f000000/Hierarchical-Rough-Terrain-Motion-Planning-using-an-Optimal-Sampling-Based-Method.pdf

      Creating occupancy map: https://www.scitepress.org/Papers/2012/40334/pdf/index.html -> to share with perception team if they want

      Control:

      Current System (Severely lacking, high potential): • PurePursuit ○ Tracking algorithm enabling the vehicle’s steering wheel to smoothly adjust steering angle in relation to the curve of the given trajectory. ○ ***Possibly can breakdown this algorithm and apply similar smoothing to other aspects of our vehicle’s movement, such as velocity, acceleration, breaking.

      Input: Final, Unidisputed Trajectory: Set of discrete points, x(t), in a local coordinate system taken at time t0 Current Vehicle State Coordinate transform history between t0 and now

      Output: Commands to hardware on vehicle

      Planned System: • PurePursuit likely kept ○ Possibly expanded/using similar approaches to smoothing velocity along trajectory • Input: ○ Final, Unidisputed Trajectory: Set of discrete points (waypoints), x(t) or v(t) [Depends on RRT and how we determine cost-effective routes) • Output: ○ Precise commands to vehicle hardware ▪ Steering ▪ Pedal ▪ Break ○ Communicate with HFE team PurePursuit More PurePursuit

      diff --git a/docs/_site/planning/planning-overview.html b/docs/_site/planning/planning-overview.html index 11400914d..0f26457ee 100755 --- a/docs/_site/planning/planning-overview.html +++ b/docs/_site/planning/planning-overview.html @@ -1 +1 @@ - Planning | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      The car should follow three instructions, in order of priority:

      1. Don’t run into anything.
      2. Drive forward along a route until the goal is reached.
      3. Obey traffic laws.

      The car should be rewarded for obeying these three instructions, and the Planning system’s objective should be to maximize this reward.

      To help the car make appropriate decisions, we can feed it “costmaps” that represent the reward that the car will receive if it drives through a given spot on the map. Each costmap might represent a specific quality (the drivable surfaces near the car, for example), and we can simply take the weighted sum of each costmap to generate a hollistic overview for the car.

      Keep in mind that “cost” and “reward” are really the same concept. The car’s goal is to select a path that moves through regions of the greatest reward, a.k.a. of the least cost.

      The more costmaps we sum together and the more carefully we select the weights for the sum, the better our car will be at making decisions.

      Costmaps

      Here are the costmaps that we should calculate at minimum, along with their justification:

      Drivable area

      This describes a surface that the car is allowed to drive over, mainly lanes, parking spaces, and intersections.

      We can expand this drivable area if the car’s current options are exhausted. For example, the default drivable area may only include lanes that match the car’s current driving direction, but this region can be expanded to include lanes with oncoming traffic if the current region is blocked.

      Justification: The car should only be allowed to drive on “drivable” surfaces: no sidewalks, lawns, etc.

      Suggested format: 0.4m cell size, 40m range.

      Example where drivable region expansion may be useful Above: Example where drivable region expansion may be useful. Credit: CARLA Leaderboard.

      Predicted occupancy

      Occupancy grids are a common concept in robotics used to describe obstacles. The world is divided into cells. If a given cell contains an obstacle, then it is marked as occupied.

      Using machine learning, we can generate occupancy grids not just for the present ($t=0$), but also for the future (such as $t=3s$).

      For a simple costmap that compresses all temporal considerations into the present, we can simply add the predicted occupancies across all frames, creating a single costmap for both the current and future occupancies.

      Justification: The car should not run into anything.

      Suggested format: 0.4m, 20m range minimum, 40m ideal.

      Distance to route & goal

      This is a combined costmap that describes both how far the car is from the route and from the goal.

      Justification: The car should drive along the route until the goal is reached.

      Costmap specifications

      1. All costmaps should be in the map frame, aligned with the x/y axes of the map. This eliminates the need to perform costly transforms.
      2. All costmaps should have resolutions (cell sizes) that are multiples of the same base resolution. Example: 0.4, 0.8, and 1.6 meters. This allows them to be cleanly scaled.
      3. The costmaps do not necessarily need to share an origin nor size, though their sum will only be accurate in the region where they align.
      + Planning | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      The car should follow three instructions, in order of priority:

      1. Don’t run into anything.
      2. Drive forward along a route until the goal is reached.
      3. Obey traffic laws.

      The car should be rewarded for obeying these three instructions, and the Planning system’s objective should be to maximize this reward.

      To help the car make appropriate decisions, we can feed it “costmaps” that represent the reward that the car will receive if it drives through a given spot on the map. Each costmap might represent a specific quality (the drivable surfaces near the car, for example), and we can simply take the weighted sum of each costmap to generate a hollistic overview for the car.

      Keep in mind that “cost” and “reward” are really the same concept. The car’s goal is to select a path that moves through regions of the greatest reward, a.k.a. of the least cost.

      The more costmaps we sum together and the more carefully we select the weights for the sum, the better our car will be at making decisions.

      Costmaps

      Here are the costmaps that we should calculate at minimum, along with their justification:

      Drivable area

      This describes a surface that the car is allowed to drive over, mainly lanes, parking spaces, and intersections.

      We can expand this drivable area if the car’s current options are exhausted. For example, the default drivable area may only include lanes that match the car’s current driving direction, but this region can be expanded to include lanes with oncoming traffic if the current region is blocked.

      Justification: The car should only be allowed to drive on “drivable” surfaces: no sidewalks, lawns, etc.

      Suggested format: 0.4m cell size, 40m range.

      Example where drivable region expansion may be useful Above: Example where drivable region expansion may be useful. Credit: CARLA Leaderboard.

      Predicted occupancy

      Occupancy grids are a common concept in robotics used to describe obstacles. The world is divided into cells. If a given cell contains an obstacle, then it is marked as occupied.

      Using machine learning, we can generate occupancy grids not just for the present ($t=0$), but also for the future (such as $t=3s$).

      For a simple costmap that compresses all temporal considerations into the present, we can simply add the predicted occupancies across all frames, creating a single costmap for both the current and future occupancies.

      Justification: The car should not run into anything.

      Suggested format: 0.4m, 20m range minimum, 40m ideal.

      Distance to route & goal

      This is a combined costmap that describes both how far the car is from the route and from the goal.

      Justification: The car should drive along the route until the goal is reached.

      Costmap specifications

      1. All costmaps should be in the base_link frame, centered on the vehicle.
      2. All costmaps should have resolutions (cell sizes) that are multiples of the same base resolution. Example: 0.4, 0.8, and 1.6 meters. This allows them to be cleanly scaled.
      3. The costmaps do not necessarily need to share an origin nor size, though their sum will only be accurate in the region where they align.
      diff --git a/docs/_site/sensing/sensing-overview.html b/docs/_site/sensing/sensing-overview.html index f72d71ea5..8cfeb166b 100755 --- a/docs/_site/sensing/sensing-overview.html +++ b/docs/_site/sensing/sensing-overview.html @@ -1 +1 @@ - Sensing | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Sensing overview

      Table of contents


      The Sensing system is responsible for processing raw sensor data into a usable form for the Perception system.

      For example, raw LiDAR data from our front and rear sensors is merged into a single reference frame, downsampled, and cropped to remove points along the vehicle itself (points of our vehicle’s doors, for example).

      More info to come! But our filters aren’t reinvinting the wheel.

      + Sensing | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Sensing overview

      Table of contents


      The Sensing system is responsible for processing raw sensor data into a usable form for the Perception system.

      For example, raw LiDAR data from our front and rear sensors is merged into a single reference frame, downsampled, and cropped to remove points along the vehicle itself (points of our vehicle’s doors, for example).

      More info to come! But our filters aren’t reinvinting the wheel.

      diff --git a/docs/_site/simulation/simulation-overview.html b/docs/_site/simulation/simulation-overview.html index 51ce33d4d..7ab4411c0 100755 --- a/docs/_site/simulation/simulation-overview.html +++ b/docs/_site/simulation/simulation-overview.html @@ -1,2 +1,2 @@ - Simulation | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

      Simulation overview

      Maintained by Connor Scally & Daniel Vayman

      Table of contents

      1. Simulation Enviroment
      2. Launching the simulator & running Navigator:
      3. Using the Simulator:
      4. Troubleshooting:
      5. Sourcing Foxy Automatically in Bash:

      Before demonstrating our codebase on the vehicle, in the real world, we must first test our stack in a virtual one. The following documentation outlines essential CARLA usage and syntax, to allow for simulating our stack in a virtual enviroment.

      Nova utilizes CARLA for virtualization. For further information on CARLA, and to learn more about advanced usage, please see the following links:

      • https://carla.org/
      • https://carla.readthedocs.io/en/latest/

      Simulation Enviroment

      • Prerequisites:

        1. CARLA Simulator: Please follow the instructions in the above links to install CARLA on your chosen operating system
        2. Navigator: Please see our GitHub page for the latest releases of Navigator
        3. RVIZ (Or an equivalent ROS visualizer)
        4. ROS2
        5. Dependencies for the above: Self-explanatory, Navigator comes with most of what you need, CARLA may not, do not forget to check!

      Launching the simulator & running Navigator:

      • Launching CARLA:

        1. Your first step should be to navigate to your CARLA directory and launch CARLA with the CARLAUE4.sh script with the -RenderOffScreen flag. If you are on a unix system, the command will look like this:
          $ /home/share/carla/CarlaUE4.sh -RenderOffscreen
        +          Simulation | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

        Simulation overview

        Maintained by Connor Scally & Daniel Vayman

        Table of contents

        1. Simulation Enviroment
        2. Launching the simulator & running Navigator:
        3. Using the Simulator:
        4. Troubleshooting:
        5. Sourcing Foxy Automatically in Bash:

        Before demonstrating our codebase on the vehicle, in the real world, we must first test our stack in a virtual one. The following documentation outlines essential CARLA usage and syntax, to allow for simulating our stack in a virtual enviroment.

        Nova utilizes CARLA for virtualization. For further information on CARLA, and to learn more about advanced usage, please see the following links:

        • https://carla.org/
        • https://carla.readthedocs.io/en/latest/

        Simulation Enviroment

        • Prerequisites:

          1. CARLA Simulator: Please follow the instructions in the above links to install CARLA on your chosen operating system
          2. Navigator: Please see our GitHub page for the latest releases of Navigator
          3. RVIZ (Or an equivalent ROS visualizer)
          4. ROS2
          5. Dependencies for the above: Self-explanatory, Navigator comes with most of what you need, CARLA may not, do not forget to check!

        Launching the simulator & running Navigator:

        • Launching CARLA:

          1. Your first step should be to navigate to your CARLA directory and launch CARLA with the CARLAUE4.sh script with the -RenderOffScreen flag. If you are on a unix system, the command will look like this:
            $ /home/share/carla/CarlaUE4.sh -RenderOffscreen
           
        • The “RenderOffscreen” flag hides the rendering window, which saves some resources. See here for more details

        • Launching RVIZ (within our Docker container):

          1. Open a new terminal window.

          2. Navigate to the root directory of Navigator

          3. Enable Docker to launch GUI programs

            $ xhost +

          4. Run our docker container start script. (If first time running container, refer to step 3)

            $ ./start.sh

          5. Source the setup script via a command like: . install/setup.bash

          6. Run: rviz2
          7. Select File followed by Open Config Select default.rviz from the share folder. It is recommended that you have your own copy of this as well for your own configuration.
        • Launching Navigator:

          1. Open a new terminal window.

          2. Navigate to the root directory of Navigator.

          3. Run the docker container ./start.sh

          4. Run source /install/setup.bash (if you have bash sourcing ROS automatically (see below), that works too)

          5. Run ros2 launch carla_interface carla-lite.launch.py

          6. Check RVIZ and terminal output. The sim_bridge will publish sensor data just as if you were driving on campus, and it will similary accept commands from our standard topics. As of writing, our custom bridge publishes:

          • GNSS (GPS)
          • IMU
          • Front and rear Lidar (not fully functional)
          • Front RGB camera
          • Front depth camera
          • CARLA ground truths for
          • Car’s odometry (position, orientation, speed)
          • CARLA virtual bird’s-eye camera (/carla/birds_eye_rgb)

          The most up-to-date information on our bridge’s capabilities can be found at the top of the script itself.

        Using the Simulator:

        • You can control our ego vehicle with ros2 run manual_control manual_control_node
          • At the moment, this only supports keyboard control through NoMachine or similar, not SSH.
          • If you get a “pynput” error, try running pip3 install pynput.
        • You can change a number of simulation settings by editing our script’s contants (here).
          • Don’t forget to rebuild the package or use colcon build --symlink-install (recommended).
          • ROS param support in the works.

        Troubleshooting:

        • If you get a “pynput” error, try running pip3 install pynput.
        • If you get a CARLA segmentation fault, it’s likely you just need to restart CARLA. This will be fixed… eventually. This should only happen after starting the bridge 10 times or so, and should not happen while the bridge is running.
        • If CARLA gives you a SIGFAULT error attach the -carla-rpc-port=N where N = your favorite (Not in use) port number.

        Sourcing Foxy Automatically in Bash:

        1. Open your terminal
        2. Write the command –> gedit ~/.bashrc (or nano, whatever really)
        3. Go under the last line line and write –> source /opt/ros/foxy/setup.bash
        4. Save and exit
        5. Now with every new shell you open, it will source automatically
        diff --git a/docs/_site/system-overview.html b/docs/_site/system-overview.html index 10f54fb6a..83d7f1c83 100755 --- a/docs/_site/system-overview.html +++ b/docs/_site/system-overview.html @@ -1 +1 @@ - System overview | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

        System overview

        Maintained by Will Heitman

        Table of contents

        1. Design
        2. Subsystems
          1. Example

        Design

        Navigator is designed to be:

        • Simple, with components that are easy to use an extend
          • When a more powerful but complex algorithm is used, a simpler alternative should also be present
        • Modular, with nodes that can be swapped, added, and updated with the help of ROS2
          • Since nodes are all built using standard C++ and Python libraries, code is future-proofed.
        • Open source, with all of our code licensed under the highly permissable MIT license
          • Our dependencies are also open-source

        Subsystems

        Navigator's general structure

        Navigator is split into five main subsystems:

        • Sensing, where raw sensor data from cameras, GNSS, and more is filtered before being passed along
        • Perception, which uses the filtered sensor data to build a rich understanding of the car’s surroundings
        • Planning, which uses this rich understanding, plus the desired destination, to decide how the car should act on a high level
        • Controls, where the desired action is compared to the car’s current state and low-level action is calculated
        • Interface, where the low-level action is sent to the steering wheel and pedals.

        We also have some important code to support testing, visualization, and simulation. Simulation plays a big role in our development, and you can find an overview of it here.

        Example

        Our sensing system takes in a red blob from our front camera and does some white balancing to make the image more clear. The perception system identifies this red blob as a stop sign and generates a bounding box with the coordinates of the stop sign relative to the car. The planning system determines that we must set our speed to zero at the stop sign. The controls system notes that our car is still moving, and calculates that we must decelerate a certain amount. Finally, our actuation system converts this desired deceleration into a brake pedal command, which is sent out to the pedal’s motor.

        + System overview | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

        System overview

        Maintained by Will Heitman

        Table of contents

        1. Design
          1. About nodes and topics
        2. Subsystems
        3. Cost maps
        4. Topics

        Design

        Navigator is designed to be:

        • Simple, with components that are easy to use an extend
          • When a more powerful but complex algorithm is used, a simpler alternative should also be present
        • Modular, with nodes that can be swapped, added, and updated with the help of ROS2
          • Since nodes are all built using standard C++ and Python libraries, code is future-proofed.
        • Open source, with all of our code licensed under the highly permissable MIT license
          • Our dependencies are also open-source

        About nodes and topics

        Navigator is built upon ROS2, a communications framework where individual executables called “nodes” exchange messages throguh “topics.” A node can either subscribe to a topic or publish to it. In this fashion, individual nodes form a dense network where everything from camera streams to steering commands are passed from one node to the next.

        Nodes can be grouped into packages. Packages are then grouped in workspaces. Navigator itself is a ROS workspace. It contains many packages, and each package contains at least one node.

        Using ROS2, one node can gather raw LiDAR data from a sensor, where it publishes the pointcloud as a PointCloud2 message to a topic called /lidar/raw. Another node can then subscribe to /lidar/raw, filter the data, and publish the result to /lidar/filtered.

        To learn more about ROS, watch this lecture by Katherine Scott, a developer advocate at Open Robotics. <!– ## Subsystems Navigator's general structure

        Navigator is split into five main subsystems:

        • Sensing, where raw sensor data from cameras, GNSS, and more is filtered before being passed along
        • Perception, which uses the filtered sensor data to build a rich understanding of the car’s surroundings
        • Planning, which uses this rich understanding, plus the desired destination, to decide how the car should act on a high level
        • Controls, where the desired action is compared to the car’s current state and low-level action is calculated
        • Interface, where the low-level action is sent to the steering wheel and pedals. –>

        Subsystems

        We can divide Navigator’s nodes into four groups.

        The sensing subsystem takes raw sensor data and publishes them as Image messages, PointCloud2 messages, Imu messages, and so on. This subsystem also include sensor filters, which subscribe to raw data and publish their filtered results.

        The perception subsystem draws inferences from the sensor data, including the location of pedestrians, our position on the map, and the predicted motion of surrounding vehicles. Nodes in this subsystem often publish their results as cost maps.

        The planning subsystem takes our perception results and decides what our vehicle should do. This subsystem handles both high-level decisions (Should we pass a car that’s stopped in the road?) and low-level ones (How far should we press the throttle pedal to reach our desired speed?).

        The interface subsystem is the link between our software and hardware. It includes nodes that communicate with our steering hardware, our microcontroller, and more. Both the sensing and interface subsystems are vehicle-specific, which means that they need to be configured to suite each individual vehicle. At Nova, we have separate configurations for simulated driving and real-world use.

        Cost maps

        During execution, Navigator calculates several cost maps, which are grid-based maps of our surrounding area that describe where our car should or should not drive.

        Each cell in the grid is assigned a cost. The higher the cost, the less likely our car will generate a path that moves through the cell. This results in paths that weave their way through only low-cost cells. If no low-cost cells are available, the car stops and waits.

        We calculate and use multiple cost maps, each one representing a unique factor to consider. For example:

        • Our occupancy grid generator describes the location of objects (cars, people, curbs).
        • Our prediction network (PredNet) node describes the future location of obstacles.
        • Our red light detector marks intersections as high-cost regions if the light is red.
        • Our map manager assigns costs based on how far a cell is from the route and from the goal.

        We add as many of these layers together to form a single, holisitic costmap that our motion planner uses as its input.

        Cost map dimensions

        Above: Cost map dimensions

        Cost maps should be in the base_link (vehicle) reference frame. They should extend 40 meters in front and to the side of the car and 20 meters behind, forming a total area of 80 x 60 meters. Cells should have a side length of either 0.2, 0.4, 0.8, or 1.6 meters.

        Examples of cost maps

        In the above example, each image is 200 x 150 pixels, representing a cost map layer with a resolution of 0.4 meters/cell. Clockwise from top left: Current occupancy, junction cost (due to a stop sign), route distance, and drivable area.

        Topics

        • /lidar/fused: Raw LiDAR fused together to create a 360-degree picture. Otherwise unfiltered.
        • /lidar/filtered: Filtered LiDAR, with ground points removed.
        • /grid/drivable
        • /grid/route_distance
        • /grid/occupancy/current: Only the current occupancy grid.
        • /grid/occupancy/combined: Both the current and all future prediction occupancy grids, summed together.
        diff --git a/docs/_site/writing-documentation.html b/docs/_site/writing-documentation.html index 7bb5781a7..d82168571 100644 --- a/docs/_site/writing-documentation.html +++ b/docs/_site/writing-documentation.html @@ -1,2 +1,2 @@ - Writing documentation | Navigator Skip to main content Link Menu Expand (external link) Document Search Copy Copied

        System overview

        Table of contents

        1. Testing locally
        2. Editing online

        This documentation site is built off of Navigator’s dev branch. All files within the /doc directory are remapped to nova-utd.github.io.

        Adding to the site is easy. Here are two good options:

        Testing locally

        To test locally, cd into /docs and run

        docker run --rm --volume="$PWD:/srv/jekyll:Z" -p 8083:8083 jekyll/jekyll jekyll serve --port 8083
        +          Writing documentation | Navigator                 Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

        System overview

        Table of contents

        1. Testing locally
        2. Editing online

        This documentation site is built off of Navigator’s dev branch. All files within the /doc directory are remapped to nova-utd.github.io.

        Adding to the site is easy. Here are two good options:

        Testing locally

        To test locally, cd into /docs and run

        docker run --rm --volume="$PWD:/srv/jekyll:Z" -p 8083:8083 jekyll/jekyll jekyll serve --port 8083
         

        Use a browser to view localhost:8083. Refresh the page to show the latest updates. See the official Docker README for more info.

        Editing online

        On GitHub, move to the /docs directory on the dev branch (here), then press the period key on your keyboard. This will open GitHub’s web editor. See here for more info.

        diff --git a/docs/assets/res/airbags.png b/docs/assets/res/airbags.png new file mode 100644 index 000000000..5b60b868f Binary files /dev/null and b/docs/assets/res/airbags.png differ diff --git a/docs/assets/res/airbags.xcf b/docs/assets/res/airbags.xcf new file mode 100644 index 000000000..ff1f12f63 Binary files /dev/null and b/docs/assets/res/airbags.xcf differ diff --git a/docs/assets/res/cost_map_size.jpg b/docs/assets/res/cost_map_size.jpg new file mode 100644 index 000000000..b97c489c8 Binary files /dev/null and b/docs/assets/res/cost_map_size.jpg differ diff --git a/docs/assets/res/cost_maps.png b/docs/assets/res/cost_maps.png new file mode 100644 index 000000000..f5a1f0cec Binary files /dev/null and b/docs/assets/res/cost_maps.png differ diff --git a/docs/assets/res/logo-alt.gif b/docs/assets/res/logo-alt.gif new file mode 100644 index 000000000..efe6fe38d Binary files /dev/null and b/docs/assets/res/logo-alt.gif differ diff --git a/docs/assets/res/routing-sections.png b/docs/assets/res/routing-sections.png new file mode 100644 index 000000000..9e7d2bedd Binary files /dev/null and b/docs/assets/res/routing-sections.png differ diff --git a/docs/contributing/tricks.md b/docs/contributing/tricks.md new file mode 100755 index 000000000..37ea15663 --- /dev/null +++ b/docs/contributing/tricks.md @@ -0,0 +1,31 @@ +--- +layout: default +title: Tricks +nav_order: 5 +--- + +# Tricks + +{: .no_toc } + +_Maintained by Nova members_ + +## Table of contents + +{: .no_toc .text-delta } + +1. TOC + {:toc} + +--- + +## Tools + +- You can get the publishing frequency of a topic with `$ ros2 topic hz [topic_name]` +- Show a graph of all current topics and nodes with `$ rqt_graph` +- VS Code's "Remote - SSH" extension is a good way to develop remotely on the Quad. Files, terminals, and more all appear as though you were working locally on the Quad. +- Other useful VS Code extensions include Prettier, GitLens, Doxygen Documenttion Generator (C++), autoDocstring (Python), and the C/C++ entension pack. + +## Other + +- ROS [Services](https://docs.ros.org/en/foxy/Tutorials/Beginner-Client-Libraries/Writing-A-Simple-Py-Service-And-Client.html) are alternatives to publishers/subscribers. They return results only when requested by a Client. diff --git a/docs/index.md b/docs/index.md index a6bfb7f1a..3c1a0f22f 100755 --- a/docs/index.md +++ b/docs/index.md @@ -13,11 +13,9 @@ Despite major advances in autonomous driving research, there has yet to exist a Navigator is our answer to this delimma. It's built on standard technologies, is kept as simple as possible, and its modular design makes adding new features straightforward. ## System requirements -- System running Ubuntu 20.04 LTS or similar ([see here](http://docs.ros.org.ros.informatik.uni-freiburg.de/en/foxy/Installation/Alternatives/Ubuntu-Development-Setup.html#system-requirements)) - - *[**Docker**](https://docs.docker.com/desktop/) engine already installed on Ubuntu* -- [**Ros2 Foxy**](https://docs.ros.org/en/foxy/Installation.html) -- [**CARLA 0.9.13**](https://carla.readthedocs.io/en/latest/start_quickstart/) -- A dedicated GPU with at least 6 GB of memory, ideally 8 GB +- [**Docker**](https://docs.docker.com/desktop/) +- [**CARLA 0.9.13**](https://carla.readthedocs.io/en/latest/start_quickstart/) for simulated testing (optional) +- For best results, a dedicated GPU with at least 6 GB of memory, ideally 8 GB - x86_64 CPU - About 20 GB of disk space @@ -25,9 +23,9 @@ Navigator is our answer to this delimma. It's built on standard technologies, is > Note: Lines with "$" are on host, while lines with "#" are within the container. -1. [Install ROS2 Foxy](https://docs.ros.org/en/foxy/Installation.html) if you haven't already done so -2. [Install Docker](https://www.docker.com/get-started/) if you haven't already done so -3. Clone our repository +1. [Install Docker](https://www.docker.com/get-started/) if you haven't already done so +2. If not already set, choose a number between 0-100 and use this for your user-wide ROS_DOMAIN_ID. Add this to your `.bashrc` with `echo 'export ROS_DOMAIN_ID=[your number]' >> ~/.bashrc` +2. Clone our repository ``` $ git clone --recursive https://github.com/Nova-UTD/navigator $ cd navigator @@ -39,7 +37,7 @@ $ ./docker.sh ``` which gives: ``` -wheitman@justingpu:~/navigator$ ./docker.sh +[username]@justingpu:~/navigator$ ./docker.sh ===================================================================== ▀█▄ ▀█▀ ██ ▄ █▀█ █ ▄▄▄▄ ▄▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄ ▄▄▄▄ ▄██▄ ▄▄▄ ▄▄▄ ▄▄ @@ -72,7 +70,7 @@ That's it! $ ./docker.sh ... root@yourhost:/navigator# ./navigator -root@yourhost:/navigator# ros2 launch carla_interface carla-lite.launch.py +root@yourhost:/navigator# ros2 launch carla_interface carla.launch.py ``` This should start a series of ROS nodes, spawning an ego vehicle in the simulator along with a number of sensors: ``` @@ -91,3 +89,8 @@ $ ./docker.sh ... root@yourhost:/navigator# rviz2 ``` + +## Real-world use +To run in the real-world, you'll need to provide your own LiDAR stream, map data, and throttle/brake/steering interface. We provide our own interface, for use with our specific hardware, as an example. + +To use, run `./docker.sh` to enter the container, then source Navigator with `. install/setup.bash`, and finally launch the real-world script with `ros2 launch main.launch.py`. If you haven't built the workspace yet, run `colcon build --symlink-install` after sourcing. diff --git a/docs/perception/segmentation.md b/docs/perception/segmentation.md new file mode 100644 index 000000000..89e99e860 --- /dev/null +++ b/docs/perception/segmentation.md @@ -0,0 +1,54 @@ +--- +layout: default +title: Semantic segmentation +nav_order: 3 +--- + +# Semantic segmentation + +{: .no_toc } + +_Maintained by Will Heitman_ + +## Table of contents + +{: .no_toc .text-delta } + +1. TOC + {:toc} + +--- + +## Class dictionary + +Our semantic segmentation model is trained on the [Cityscapes Dataset](https://www.cityscapes-dataset.com/). + +| Description | Class ID (int) | RGB | Unpacked | +| --------------------------------------- | -------------- | ----------------------------------------------------------- | ---------- | +| Road | 0 | (128, 64, 128) | 4286595200 | +| Sidewalk | 1 | (244, 35, 232) | 4294190056 | +| ~~Building~~ (overwritten by wall) | 2 | | | +| Wall | 3 | (102,102,156) | ? | +| ~~Fence~~ (overwritten by wall) | 4 | | | +| Pole | 5 | (153, 153, 153) | 4288256409 | +| Traffic light | 6 | (250, 170, 30) | 4294617630 | +| Traffic sign | 7 | (220, 220, 0) | 4292664320 | +| Vegetation | 8 | (107, 142, 35) | ? | +| Terrain | 9 | (145, 170, 100) | 4287736420 | +| Sky | 10 | (70, 130, 180) | ? | +| Person | 11 | (220, 20, 60) | ? | +| ~~Rider~~ (overwritten by Car) | 12 | | | +| Car | 13 | (0, 0, 142) | 4278190222 | +| ~~Truck~~ (overwritten by Car) | 14 | | | +| ~~Bus~~ (overwritten by Car) | 15 | | | +| ~~Train~~ (overwritten by Car) | 16 | | | +| ~~Motorcycle~~ (overwritten by Bicycle) | 17 | | | +| Bicycle | 18 | (119, 11, 32) | 4285991711 | + +```python +import struct +r,g,b = 119,11,31 +a = 255 # always +unpacked = struct.unpack('I', struct.pack('BBBB', b, g, r, a))[0] # 4285991711 +``` + diff --git a/docs/planning/airbags.md b/docs/planning/airbags.md new file mode 100644 index 000000000..aa8117b9d --- /dev/null +++ b/docs/planning/airbags.md @@ -0,0 +1,20 @@ +--- +layout: default +title: Airbags +--- + +# Airbags + +_Maintained by Will Heitman_ + +"Airbags" are what we call safety zones that limit our vehicle's speed. Airbags form a low-level safety system that is one step above a similar automatic emergency braking (AEB) system. + +The logic is simple. We establish three safety zones (red, amber, and yellow), where our speed is limited to varying degrees. If any region within these zones is occupied by a LiDAR point, the vehicle's speed will be limited to the zone's value. If no LiDAR point falls within the zone, the speed is not limited. + +In the case of a speed limitation, if the car is currently traveling faster than the zone allows, the airbag system will send a 100% brake command. + +Airbags extend in front of the vehicle, and slightly to either side. + +![Diagram of airbag dimensions](/navigator/assets/res/airbags.png) + +Above: Diagram of airbag dimensions diff --git a/docs/planning/maps.md b/docs/planning/maps.md new file mode 100644 index 000000000..400f284d5 --- /dev/null +++ b/docs/planning/maps.md @@ -0,0 +1,43 @@ +--- +layout: default +title: Maps +--- + +# Maps + +{: .no_toc } + +_Maintained by Will Heitman_ + +## Table of contents + +{: .no_toc .text-delta } + +1. TOC + {:toc} + +## Grid maps + +All grid maps are in the `base_link` (vehicle) reference frame. The semantic grid extends 40 meters ahead, 20 meters behind, and 30 meters to either side of the car. +![Cost map dimensions](assets/res/cost_map_size.jpg) + +--- + +## Semantic map + +This is a general-purpose grid map drawn from OpenDRIVE map data, where each cell is tagged with an appropriate class. + +| ID | Description | Class | Name | Included? | +| ---- | ------------------------------------------------------------ | ------ | ---------------------------------- | --------- | +| 0 | None/unknown. Grass, buildings, and other regions not described in the OpenDRIVE map. | | ✅ | | +| 1 | Driving lane | Lane | ✅ | | +| 2 | Shoulder | Lane | ✅ | | +| 3 | Curb | Lane | ✅ | | +| 4 | Sidewalk | Lane | ✅ | | +| 5 | Median | Lane | ✅ | | +| 6 | Parking | Lane | ✅ | | +| 11 | Stop sign | Signal | `Sign_Stop` | | +| 12 | Speed limit sign | Object | `Speed_30`, `Speed_60`, `Speed_90` | | +| 13 | Traffic light | Signal | `Signal_3Light_Post01` | | +| 21 | Crosswalk | Object | `CContinentalCrosswalk` | | + diff --git a/docs/planning/planning-overview.md b/docs/planning/planning-overview.md index 008afff99..1ae9af5dd 100755 --- a/docs/planning/planning-overview.md +++ b/docs/planning/planning-overview.md @@ -4,23 +4,26 @@ title: Planning --- The car should follow three instructions, in order of priority: + 1. Don't run into anything. 2. Drive forward along a route until the goal is reached. 3. Obey traffic laws. -The car should be *rewarded* for obeying these three instructions, and the Planning system's objective should be to maximize this reward. +The car should be _rewarded_ for obeying these three instructions, and the Planning system's objective should be to maximize this reward. -To help the car make appropriate decisions, we can feed it "costmaps" that represent the reward that the car will receive if it drives through a given spot on the map. Each costmap might represent a specific quality (the drivable surfaces near the car, for example), and we can simply take the *weighted sum* of each costmap to generate a hollistic overview for the car. +To help the car make appropriate decisions, we can feed it "costmaps" that represent the reward that the car will receive if it drives through a given spot on the map. Each costmap might represent a specific quality (the drivable surfaces near the car, for example), and we can simply take the _weighted sum_ of each costmap to generate a hollistic overview for the car. Keep in mind that "cost" and "reward" are really the same concept. The car's goal is to select a path that moves through regions of the greatest reward, a.k.a. of the least cost. The more costmaps we sum together and the more carefully we select the weights for the sum, the better our car will be at making decisions. # Costmaps + Here are the costmaps that we should calculate at minimum, along with their justification: ## Drivable area -This describes a surface that the car is allowed to drive over, mainly lanes, parking spaces, and intersections. + +This describes a surface that the car is allowed to drive over, mainly lanes, parking spaces, and intersections. We can expand this drivable area if the car's current options are exhausted. For example, the default drivable area may only include lanes that match the car's current driving direction, but this region can be expanded to include lanes with oncoming traffic if the current region is blocked. @@ -32,6 +35,7 @@ Suggested format: 0.4m cell size, 40m range. Above: Example where drivable region expansion may be useful. Credit: CARLA Leaderboard. ## Predicted occupancy + Occupancy grids are a common concept in robotics used to describe obstacles. The world is divided into cells. If a given cell contains an obstacle, then it is marked as occupied. Using machine learning, we can generate occupancy grids not just for the present ($t=0$), but also for the future (such as $t=3s$). @@ -40,14 +44,16 @@ For a simple costmap that compresses all temporal considerations into the presen Justification: The car should not run into anything. -Suggested format: 0.4m, 20m range *minimum*, 40m ideal. +Suggested format: 0.4m, 20m range _minimum_, 40m ideal. ## Distance to route & goal + This is a combined costmap that describes both how far the car is from the route and from the goal. Justification: The car should drive along the route until the goal is reached. # Costmap specifications -1. All costmaps should be in the `map` frame, aligned with the x/y axes of the map. This eliminates the need to perform costly transforms. + +1. All costmaps should be in the `base_link` frame, centered on the vehicle. 2. All costmaps should have resolutions (cell sizes) that are multiples of the same base resolution. Example: 0.4, 0.8, and 1.6 meters. This allows them to be cleanly scaled. -3. The costmaps do not necessarily need to share an origin nor size, though their sum will only be accurate in the region where they align. \ No newline at end of file +3. The costmaps do not necessarily need to share an origin nor size, though their sum will only be accurate in the region where they align. diff --git a/docs/planning/routes.md b/docs/planning/routes.md new file mode 100644 index 000000000..c38b37336 --- /dev/null +++ b/docs/planning/routes.md @@ -0,0 +1,57 @@ +--- +layout: default +title: Routes +--- + +# Routes + +_Maintained by Will Heitman_ + +A route is a sequence of poses that our AV is encouraged to follow. At its simplest, a route constitutes the start and goal poses. However, routes can contain many poses in between. + +The AV's goal is to _loosely_ follow the poses contained in the route. How loosely? That depends on the priorities given to the downstream motion planner. In general, though, we consider that the AV has reached a pose along the route when it is within about 10 meters. That means that if we drive through the lane adjacent to the pose, or if we park the vehicle near the goal pose, for example, the route is still satisfied. + +This loose approach is in contrast to the specific path that the downstream motion planner calculates. That path, which factors in the route as well as occupancy and other perception data, serves as a precise target for the car. In other words, the car does not have to drive over the route, but it should drive over the motion planner's path. + +As an example, consider making a turn at an intersection. The route planner will set the route to be the precise centerline of the turn lane, but human drivers will follow a curve that bends slightly away from the center, creating a smoother ride. We want to give Navigator the flexibility to make these kinds of adjustments. + +## Route format + +Let's define some operational constraints on the route. + +First, the route will be formatted as a standard ROS [Path](http://docs.ros.org/en/noetic/api/nav_msgs/html/msg/Path.html) message, where each pose is stamped with a timestamp reflecting the general goal arrival time. For example, the final pose in the Path message (that is, the goal pose of the route) may have a timestamp set to fifteen minutes past the current time for a neighborhood route four miles long. + +Second, these goal timestamps should be taken lightly. Unlike the timestamp from the motion planner, these should serve as loose targets, just like the poses themselves. + +Third, the route should be updated routinely to ensure that any poses already reached are removed from the route. In other words, all poses in the latest route should be ahead of the car in terms of route progression. + +Fourth, the route should be divided into a **refined** and a **rough** section. In the rough section, the route poses have _no maximum spacing_. The rough section should have the goal pose as its final point, and it should always succeed the refined section. + +The refined section extends from the car's current position to the area immediately ahead in the route, with the section's length determined by a "lookahead distance" set as a node parameter. In the refined section, the route poses should have a spacing of between 0.5-10 meters (see the table below). + +As the car progresses along the route, the refined section will move with it, refining more and more of the route. When the goal pose is sufficiently close, the refined section will cover the entirety of the remaining route, and the rough section will be empty. + +![Route sections](assets/res/routing-sections.png) + +### Message + +``` +# Path.msg containing the route +std_msgs/Header header +geometry_msgs/PoseStamped[] poses +``` + +### Parameters + +| Parameter | Worst case | Best case | +| --------------------------------------------- | ------------------------------- | ----------------------------------- | +| Spacing between refined section as crow flies | 10m (seen along straight roads) | 0.5 meters (seen along tight turns) | +| | | | +| | | | + +## Route generation + +1. Receive rough route from CARLA +2. Get closest route point to car +3. Trim all points not within interval (closestPoint, goalPoint), where the goal point is the final point in the list +4. While distanceFromCar < some param, insert refined points. using HD map data for lane centerlines diff --git a/docs/system-overview.md b/docs/system-overview.md index e52a54370..86cd9030e 100755 --- a/docs/system-overview.md +++ b/docs/system-overview.md @@ -27,7 +27,16 @@ Navigator is designed to be: - **Open source**, with all of our code licensed under the highly permissable MIT license - Our dependencies are also open-source -## Subsystems +### About nodes and topics +Navigator is built upon ROS2, a communications framework where individual executables called "nodes" exchange messages throguh "topics." A node can either subscribe to a topic or publish to it. In this fashion, individual nodes form a dense network where everything from camera streams to steering commands are passed from one node to the next. + +Nodes can be grouped into packages. Packages are then grouped in workspaces. Navigator itself is a ROS workspace. It contains many packages, and each package contains at least one node. + +{: .example} +Using ROS2, one node can gather raw LiDAR data from a sensor, where it publishes the pointcloud as a `PointCloud2` message to a topic called `/lidar/raw`. Another node can then subscribe to `/lidar/raw`, filter the data, and publish the result to `/lidar/filtered`. + +To learn more about ROS, watch [this lecture by Katherine Scott](https://www.youtube.com/watch?v=FTA4Ia2vLS8), a developer advocate at Open Robotics. + + + + + + +## Subsystems +We can divide Navigator's nodes into four groups. + +The **sensing** subsystem takes raw sensor data and publishes them as [`Image`](https://docs.ros.org/en/indigo/api/sensor_msgs/html/msg/Image.html) messages, [`PointCloud2`](https://docs.ros.org/en/indigo/api/sensor_msgs/html/msg/PointCloud2.html) messages, [`Imu`](https://docs.ros.org/en/indigo/api/sensor_msgs/html/msg/Imu.html) messages, and so on. This subsystem also include sensor filters, which subscribe to raw data and publish their filtered results. + +The **perception** subsystem draws inferences from the sensor data, including the location of pedestrians, our position on the map, and the predicted motion of surrounding vehicles. Nodes in this subsystem often publish their results as [**cost maps**](#cost-maps). + +The **planning** subsystem takes our perception results and decides what our vehicle should do. This subsystem handles both high-level decisions (Should we pass a car that's stopped in the road?) and low-level ones (How far should we press the throttle pedal to reach our desired speed?). + +The **interface** subsystem is the link between our software and hardware. It includes nodes that communicate with our steering hardware, our microcontroller, and more. Both the sensing and interface subsystems are **vehicle-specific**, which means that they need to be configured to suite each individual vehicle. At Nova, we have separate configurations for simulated driving and real-world use. + +## Cost maps +During execution, Navigator calculates several cost maps, which are grid-based maps of our surrounding area that describe where our car should or should not drive. + +Each cell in the grid is assigned a cost. The higher the cost, the less likely our car will generate a path that moves through the cell. This results in paths that weave their way through only low-cost cells. If no low-cost cells are available, the car stops and waits. + +We calculate and use multiple cost maps, each one representing a unique factor to consider. For example: +- Our occupancy grid generator describes the location of objects (cars, people, curbs). +- Our prediction network (PredNet) node describes the *future* location of obstacles. +- Our red light detector marks intersections as high-cost regions if the light is red. +- Our map manager assigns costs based on how far a cell is from the route and from the goal. + +We add as many of these layers together to form a single, holisitic costmap that our motion planner uses as its input. + +![Cost map dimensions](assets/res/cost_map_size.jpg) + +Above: Cost map dimensions + +Cost maps should be in the `base_link` (vehicle) reference frame. They should extend 40 meters in front and to the side of the car and 20 meters behind, forming a total area of 80 x 60 meters. Cells should have a side length of either 0.2, 0.4, 0.8, or 1.6 meters. -We also have some important code to support testing, visualization, and simulation. Simulation plays a big role in our development, and you can find an overview of it [here](/navigator/simulation/simulation-overview). +![Examples of cost maps](assets/res/cost_maps.png) -#### Example -Our **sensing** system takes in a red blob from our front camera and does some white balancing to make the image more clear. The **perception** system identifies this red blob as a stop sign and generates a bounding box with the coordinates of the stop sign relative to the car. The **planning** system determines that we must set our speed to zero at the stop sign. The **controls** system notes that our car is still moving, and calculates that we must decelerate a certain amount. Finally, our **actuation** system converts this desired deceleration into a brake pedal command, which is sent out to the pedal's motor. +In the above example, each image is 200 x 150 pixels, representing a cost map layer with a resolution of 0.4 meters/cell. Clockwise from top left: Current occupancy, junction cost (due to a stop sign), route distance, and drivable area. ## Topics - `/lidar/fused`: Raw LiDAR fused together to create a 360-degree picture. Otherwise unfiltered. diff --git a/leaderboard.bash b/leaderboard.bash index d73fd5db1..72701dd73 100755 --- a/leaderboard.bash +++ b/leaderboard.bash @@ -1,14 +1,17 @@ #!/bin/bash +echo "Sourcing Navigator" +source /navigator/install/setup.bash + echo "Starting the CARLA evaluation script." echo "This may take some time. Sit tight!" # For description of flags, see: # https://leaderboard.carla.org/get_started/#22-understanding-the-leaderboard-components python3 ${LEADERBOARD_ROOT}/leaderboard/leaderboard_evaluator.py \ ---port=2014 \ ---routes=${LEADERBOARD_ROOT}/data/routes_training.xml \ ---routes-subset="10" \ +--port=2005 \ +--routes=/navigator/data/routes_town02.xml \ +--routes-subset="0" \ --repetitions=1 \ --track=MAP \ --checkpoint=/navigator/log/checkpoints.json \ diff --git a/main.launch.py b/main.launch.py new file mode 100644 index 000000000..e0fa84c37 --- /dev/null +++ b/main.launch.py @@ -0,0 +1,197 @@ +from os import name, path, environ + +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.actions import IncludeLaunchDescription +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.actions import ExecuteProcess +from launch.conditions import IfCondition +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +from ament_index_python import get_package_share_directory + + +def generate_launch_description(): + + # leaderboard_liaison = Node( + # package='carla_interface', + # executable='liaison_node', + # parameters=[] + # ) + + lidar_processor = Node( + package='sensor_processing', + executable='lidar_processing_node' + ) + + mcl = Node( + package='state_estimation', + executable='mcl_node' + ) + + # carla_spawner = IncludeLaunchDescription( + # PythonLaunchDescriptionSource([get_package_share_directory( + # 'carla_spawn_objects'), '/carla_spawn_objects.launch.py']), + # launch_arguments={ + # 'objects_definition_file': '/navigator/data/carla_objects.json'}.items(), + # ) + + # carla_controller = Node( + # package='carla_controller', + # executable='controller' + # ) + + urdf_publisher = Node( + package='robot_state_publisher', + executable='robot_state_publisher', + arguments=[path.join("/navigator/data", "hail_bopp.urdf")] + ) + + # carla_bridge_official = IncludeLaunchDescription( + # PythonLaunchDescriptionSource([get_package_share_directory( + # 'carla_ros_bridge'), '/carla_ros_bridge.launch.py']), + # launch_arguments={ + # 'host': 'localhost', + # 'port': str(2000 + int(environ['ROS_DOMAIN_ID'])), + # 'synchronous_mode': 'True', + # 'town': 'Town02', + # 'register_all_sensors': 'False', + # 'ego_vehicle_role_name': 'hero', + # 'timeout': '30' + # }.items(), + # ) + + gnss_processor = Node( + package='state_estimation', + executable='gnss_processing_node' + ) + + mcl = Node( + package='state_estimation', + executable='mcl_node' + ) + + map_manager = Node( + package='map_management', + executable='map_management_node' + ) + + rviz = Node( + package='rviz2', + namespace='', + executable='rviz2', + name='rviz2', + arguments=['-d' + '/navigator/data/mcl.rviz'] + ) + + ground_seg = Node( + package='occupancy_cpp', + executable='ground_segmentation_exe' + ) + + image_segmentation = Node( + package='segmentation', + executable='image_segmentation_node' + ) + + semantic_projection = Node( + package='segmentation', + executable='image_projection_node' + ) + + mcu_interface = Node( + package='mcu_interface', + executable='mcu_interface_node' + ) + + joy = Node( + package='joy_linux', + executable='joy_linux_node' + ) + + joy_translator = Node( + package='joy_translation', + executable='joy_translation_node' + ) + + epas = Node( + package='epas', + executable='epas_node' + ) + + linear_actuator = Node( + package='linear_actuator', + executable='linear_actuator_node' + ) + + controller = Node( + package="parade_controller", + executable="parade_controller_node" + ) + + left_lidar_driver = Node( + package = 'velodyne_driver', + executable = 'velodyne_driver_node', + parameters = ["/navigator/param/perception/lidar_driver_left.param.yaml"], + namespace='velo_left' + ) + + right_lidar_driver = Node( + package = 'velodyne_driver', + executable = 'velodyne_driver_node', + parameters = ["/navigator/param/perception/lidar_driver_right.param.yaml"], + namespace='velo_right' + + ) + + left_lidar_pointcloud = Node( + package = 'velodyne_pointcloud', + executable = 'velodyne_convert_node', + parameters = ["/navigator/param/perception/lidar_pointcloud_left.param.yaml"], + namespace='velo_left' + ) + + right_lidar_pointcloud = Node( + package = 'velodyne_pointcloud', + executable = 'velodyne_convert_node', + parameters = ["/navigator/param/perception/lidar_pointcloud_right.param.yaml"], + namespace='velo_right' + ) + + camera = Node( + package = 'camera', + executable = 'camera_node' + ) + + gps_node = Node( + package = 'nmea_navsat_driver', + executable = 'nmea_serial_driver' + ) + + + + return LaunchDescription([ + # CONTROL + # controller, + + # INTERFACE + #joy, + #joy_translator, + #epas, + #mcu_interface, + #linear_actuator, + + left_lidar_driver, + left_lidar_pointcloud, + right_lidar_driver, + right_lidar_pointcloud, + + camera, + + gps_node, + + # MISC + urdf_publisher, + # rviz, + ]) diff --git a/param/atlas/map_baselink.param.yaml b/param/atlas/map_baselink.param.yaml deleted file mode 100755 index 9428bf992..000000000 --- a/param/atlas/map_baselink.param.yaml +++ /dev/null @@ -1,22 +0,0 @@ -# param/robot_localization.param.yaml ---- -/**: - ros__parameters: - frequency: 10.0 # Estimate update frequency, Hz, double - world_frame: "map" - two_d_mode: true - - odom0: "/odom0" # xyz and yaw - odom0_config: [true, true, true, false, false, false, - false, false, false, false, false, false, - false, false, false] - - imu0: "/imu0" # Angular vel, linear acc - imu0_config: [false, false, false, true, true, true, - false, false, false, true, true, true, - true, true, true] - - # twist0: "/twist0" # Only use x velocity (speedometer) - # twist0_config: [false, false, false, false, false, false, - # true, false, false, true, true, false, - # false, false, false] \ No newline at end of file diff --git a/param/atlas/map_odom.param.yaml b/param/atlas/map_odom.param.yaml new file mode 100755 index 000000000..6ef976ba2 --- /dev/null +++ b/param/atlas/map_odom.param.yaml @@ -0,0 +1,52 @@ +# param/robot_localization.param.yaml +--- +/**: + ros__parameters: + frequency: 10.0 # Estimate update frequency, Hz, double + world_frame: "map" + two_d_mode: true + + odom0: "/odometry/gnss_raw" # xyz and yaw + odom0_config: + [ + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + ] + + imu0: "/carla/hero/imu" # Angular vel, linear acc + imu0_config: + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + ] + + # twist0: "/twist0" # Only use x velocity (speedometer) + # twist0_config: [false, false, false, false, false, false, + # true, false, false, true, true, false, + # false, false, false] diff --git a/param/atlas/odom_baselink.param.yaml b/param/atlas/odom_baselink.param.yaml new file mode 100755 index 000000000..d1838b235 --- /dev/null +++ b/param/atlas/odom_baselink.param.yaml @@ -0,0 +1,33 @@ +# param/robot_localization.param.yaml +--- +/**: + ros__parameters: + frequency: 10.0 # Estimate update frequency, Hz, double + world_frame: "odom" + base_link_frame: "hero" + two_d_mode: true + + imu0: "/carla/hero/imu" # Angular vel, linear acc + imu0_config: + [ + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + true, + true, + ] + + # twist0: "/twist0" # Only use x velocity (speedometer) + # twist0_config: [false, false, false, false, false, false, + # true, false, false, true, true, false, + # false, false, false] diff --git a/param/mapping/lio_sam.param.yaml b/param/mapping/lio_sam.param.yaml index 95c36f150..e31195da3 100755 --- a/param/mapping/lio_sam.param.yaml +++ b/param/mapping/lio_sam.param.yaml @@ -2,7 +2,7 @@ ros__parameters: # Topics - pointCloudTopic: "/lidar_front/points_raw" # Point cloud data + pointCloudTopic: "/lidar_right/points_raw" # Point cloud data imuTopic: "/zed2i/zed_node/imu/data" # IMU data odomTopic: "odometry/imu" # IMU pre-preintegration odometry, same frequency as IMU gpsTopic: "/lgsvl/gnss_odom" # GPS odometry topic from navsat, see module_navsat.launch file diff --git a/param/perception/lidar_driver_rear.param.yaml b/param/perception/lidar_driver_left.param.yaml similarity index 92% rename from param/perception/lidar_driver_rear.param.yaml rename to param/perception/lidar_driver_left.param.yaml index 795419c74..ec764dc0d 100755 --- a/param/perception/lidar_driver_rear.param.yaml +++ b/param/perception/lidar_driver_left.param.yaml @@ -1,4 +1,4 @@ -# param/perception/lidar_driver_front.param.yaml +# param/perception/lidar_driver_left.param.yaml # See: https://github.com/ros-drivers/velodyne/tree/foxy-devel/velodyne_driver /**: ros__parameters: @@ -6,7 +6,7 @@ gps_time: false # Whether to use data capture time from a GPS, or from the local time. Should only be set to True if a GPS is attached to the Velodyne. False by default. time_offset: 0.0 # An arbitrary "skew", in seconds, to add to the acquisition timestamp. Defaults to 0.0. enabled: true # Whether the device should start-up enabled or not. Defaults to True. - frame_id: "lidar_rear" # The frame_id to use when constructing the header for the packet to be published. Defaults to "velodyne". + frame_id: "lidar_left" # The frame_id to use when constructing the header for the packet to be published. Defaults to "velodyne". model: "VLP16" # The model number of the Velodyne attached. This should be one of 64E, 64E_S2, 64E_S2.1, 64E_S3, 32E, 32C, or VLP16. Defaults to 64E. rpm: 600.0 # The RPM that the Velodyne is configured for. Note that this is descriptive, not prescriptive, so this should be set to match the value configured through the Velodyne web interface. cut_angle: 6.283185307179586 # The azimuth angle at which to declare a single rotation complete. If this is less than 0, then a fixed number of packets (device-dependent) is used per rotation. This mostly works, but can vary because of variations in the hardware. If a positive number <= 2Pi, a rotation will be declared "complete" when the azimuth reported by the device reaches that value. Defaults to 2Pi. diff --git a/param/perception/lidar_driver_front.param.yaml b/param/perception/lidar_driver_right.param.yaml similarity index 92% rename from param/perception/lidar_driver_front.param.yaml rename to param/perception/lidar_driver_right.param.yaml index b79bbf013..1a2b65c0b 100755 --- a/param/perception/lidar_driver_front.param.yaml +++ b/param/perception/lidar_driver_right.param.yaml @@ -1,4 +1,4 @@ -# param/perception/lidar_driver_front.param.yaml +# param/perception/lidar_driver_right.param.yaml # See: https://github.com/ros-drivers/velodyne/tree/foxy-devel/velodyne_driver /**: ros__parameters: @@ -6,7 +6,7 @@ gps_time: false # Whether to use data capture time from a GPS, or from the local time. Should only be set to True if a GPS is attached to the Velodyne. False by default. time_offset: 0.0 # An arbitrary "skew", in seconds, to add to the acquisition timestamp. Defaults to 0.0. enabled: true # Whether the device should start-up enabled or not. Defaults to True. - frame_id: "lidar_front" # The frame_id to use when constructing the header for the packet to be published. Defaults to "velodyne". + frame_id: "lidar_right" # The frame_id to use when constructing the header for the packet to be published. Defaults to "velodyne". model: "VLP16" # The model number of the Velodyne attached. This should be one of 64E, 64E_S2, 64E_S2.1, 64E_S3, 32E, 32C, or VLP16. Defaults to 64E. rpm: 600.0 # The RPM that the Velodyne is configured for. Note that this is descriptive, not prescriptive, so this should be set to match the value configured through the Velodyne web interface. cut_angle: 6.283185307179586 # The azimuth angle at which to declare a single rotation complete. If this is less than 0, then a fixed number of packets (device-dependent) is used per rotation. This mostly works, but can vary because of variations in the hardware. If a positive number <= 2Pi, a rotation will be declared "complete" when the azimuth reported by the device reaches that value. Defaults to 2Pi. diff --git a/param/perception/lidar_front.param.yaml b/param/perception/lidar_front.param.yaml index 42745ca73..22343728d 100755 --- a/param/perception/lidar_front.param.yaml +++ b/param/perception/lidar_front.param.yaml @@ -4,6 +4,6 @@ port: 2369 cloud_size: 55000 topic: "points_raw" # UdpDriverNode strictly expects to get the topic via `declare_parameter`. - frame_id: "lidar_front" + frame_id: "lidar_right" timeout_ms: 10 rpm: 600 diff --git a/param/perception/lidar_pointcloud_rear.param.yaml b/param/perception/lidar_pointcloud_left.param.yaml similarity index 85% rename from param/perception/lidar_pointcloud_rear.param.yaml rename to param/perception/lidar_pointcloud_left.param.yaml index b5bcb888e..edadec8d0 100755 --- a/param/perception/lidar_pointcloud_rear.param.yaml +++ b/param/perception/lidar_pointcloud_left.param.yaml @@ -2,12 +2,12 @@ # See: https://github.com/ros-drivers/velodyne/tree/foxy-devel/velodyne_driver /**: ros__parameters: - calibration: "/opt/ws_vol/data/VLP16db.yaml" # The path to the calibration file for the particular device. There are a set of default calibration files to start with in the "params" subdirectory in this package. Defaults to the empty string. + calibration: "/navigator/data/VLP16db.yaml" # The path to the calibration file for the particular device. There are a set of default calibration files to start with in the "params" subdirectory in this package. Defaults to the empty string. min_range: 1.0 # The minimum range in meters that a point must be to be added to the resulting point cloud. Points closer than this are discarded. Must be between 0.1 and 10.0. Defaults to 0.9. max_range: 130.0 # The maximum range in meters that a point must be to be added to the resulting point cloud. Points further away than this are discarded. Must be between 0.1 and 200.0. Defaults to 130.0. view_direction: 0.0 # The point around the circumference of the device, in radians, to "center" the view. Combined with view_width, this allows the node to generate a pointcloud only for the given width, centered at this point. This can vastly reduce the CPU requirements of the node. Must be between -Pi and Pi, where 0 is straight ahead from the device. Defaults to 0.0. view_width: 6.283185307179586 # The width, in radians, of the view to generate for the resulting pointcloud. Combined with view_direction, this allows the node to generate a pointcloud only for the given width, centered at the view_direction point. This can vastly reduce the CPU requirements of the node. Must be between 0 and 2Pi. Defaults to 2Pi. organize_cloud: True # Whether to organize the cloud by ring (True), or to use the order as it comes directly from the driver (False). Defaults to True. target_frame: "base_link" # The coordinate frame to apply to the generated point cloud header before publishing. If the empty string (the default), the frame is passed along from the driver packet. If this frame is different than the fixed_frame, a transformation to this coordinate frame is performed while creating the pointcloud. - fixed_frame: "lidar_rear" # The fixed coordinate frame to transform the data from. + fixed_frame: "lidar_left" # The fixed coordinate frame to transform the data from. \ No newline at end of file diff --git a/param/perception/lidar_pointcloud_front.param.yaml b/param/perception/lidar_pointcloud_right.param.yaml similarity index 85% rename from param/perception/lidar_pointcloud_front.param.yaml rename to param/perception/lidar_pointcloud_right.param.yaml index d72445a8e..c85510d50 100755 --- a/param/perception/lidar_pointcloud_front.param.yaml +++ b/param/perception/lidar_pointcloud_right.param.yaml @@ -2,12 +2,12 @@ # See: https://github.com/ros-drivers/velodyne/tree/foxy-devel/velodyne_driver /**: ros__parameters: - calibration: "/opt/ws_vol/data/VLP16db.yaml" # The path to the calibration file for the particular device. There are a set of default calibration files to start with in the "params" subdirectory in this package. Defaults to the empty string. + calibration: "/navigator/data/VLP16db.yaml" # The path to the calibration file for the particular device. There are a set of default calibration files to start with in the "params" subdirectory in this package. Defaults to the empty string. min_range: 1.0 # The minimum range in meters that a point must be to be added to the resulting point cloud. Points closer than this are discarded. Must be between 0.1 and 10.0. Defaults to 0.9. max_range: 130.0 # The maximum range in meters that a point must be to be added to the resulting point cloud. Points further away than this are discarded. Must be between 0.1 and 200.0. Defaults to 130.0. view_direction: 0.0 # The point around the circumference of the device, in radians, to "center" the view. Combined with view_width, this allows the node to generate a pointcloud only for the given width, centered at this point. This can vastly reduce the CPU requirements of the node. Must be between -Pi and Pi, where 0 is straight ahead from the device. Defaults to 0.0. view_width: 6.283185307179586 # The width, in radians, of the view to generate for the resulting pointcloud. Combined with view_direction, this allows the node to generate a pointcloud only for the given width, centered at the view_direction point. This can vastly reduce the CPU requirements of the node. Must be between 0 and 2Pi. Defaults to 2Pi. organize_cloud: True # Whether to organize the cloud by ring (True), or to use the order as it comes directly from the driver (False). Defaults to True. target_frame: "base_link" # The coordinate frame to apply to the generated point cloud header before publishing. If the empty string (the default), the frame is passed along from the driver packet. If this frame is different than the fixed_frame, a transformation to this coordinate frame is performed while creating the pointcloud. - fixed_frame: "lidar_front" # The fixed coordinate frame to transform the data from. + fixed_frame: "lidar_right" # The fixed coordinate frame to transform the data from. \ No newline at end of file diff --git a/param/perception/lidar_rear.param.yaml b/param/perception/lidar_rear.param.yaml index a2d562a53..e70a83ab2 100755 --- a/param/perception/lidar_rear.param.yaml +++ b/param/perception/lidar_rear.param.yaml @@ -4,6 +4,6 @@ port: 2368 cloud_size: 55000 topic: "points_raw" # UdpDriverNode strictly expects to get the topic via `declare_parameter`. - frame_id: "lidar_rear" + frame_id: "lidar_left" timeout_ms: 10 rpm: 600 diff --git a/param/perception/pc_filter_transform_front.param.yaml b/param/perception/pc_filter_transform_front.param.yaml deleted file mode 100755 index 796e70847..000000000 --- a/param/perception/pc_filter_transform_front.param.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# config/test.param.yaml ---- -lidar_front: - point_cloud_filter_transform_node: - ros__parameters: - timeout_ms: 110 - pcl_size: 55000 - input_frame_id: "lidar_front" - output_frame_id: "base_link" - init_timeout_ms: 5000 - expected_num_subscribers: 1 - expected_num_publishers: 1 - start_angle: 4.61 # radius - end_angle: 2.85 - min_radius: 1.5 # meters - max_radius: 150.0 - static_transformer: - quaternion: - x: 0.0 - y: 0.0 - z: -0.6631354427 - w: 0.7484994220 - translation: - x: 1.43 - y: 3.35 - z: 0.7876 diff --git a/param/perception/pc_filter_transform_front_sim.param.yaml b/param/perception/pc_filter_transform_front_sim.param.yaml deleted file mode 100755 index 0e28d12ff..000000000 --- a/param/perception/pc_filter_transform_front_sim.param.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# config/test.param.yaml ---- -lidar_front: - point_cloud_filter_transform_node: - ros__parameters: - timeout_ms: 110 - pcl_size: 55000 - input_frame_id: "lidar_front" - output_frame_id: "base_link" - init_timeout_ms: 5000 - expected_num_subscribers: 1 - expected_num_publishers: 1 - start_angle: 0.0 # radians - end_angle: 6.28 - min_radius: 3.0 # meters - max_radius: 50.0 - static_transformer: - quaternion: - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - translation: - x: 1.498 - y: -0.022 - z: 1.49 diff --git a/param/perception/pc_filter_transform_rear.param.yaml b/param/perception/pc_filter_transform_rear.param.yaml deleted file mode 100755 index f8b207628..000000000 --- a/param/perception/pc_filter_transform_rear.param.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# config/test.param.yaml ---- -lidar_rear: - point_cloud_filter_transform_node: - ros__parameters: - timeout_ms: 110 - pcl_size: 55000 - input_frame_id: "lidar_rear" - output_frame_id: "base_link" # Use URDF transform - init_timeout_ms: 5000 - expected_num_subscribers: 1 - expected_num_publishers: 1 - start_angle: 3.7 # radius - end_angle: 2.0 - min_radius: 1.5 # meters - max_radius: 150.0 - static_transformer: - quaternion: - x: 0.032584 #0.0 - y: 0.0081743 #0.0 - z: 0.9693964 #0.9699438633 - w: 0.2431915 #0.2433287941 - translation: - x: 0.52 - y: -0.72 - z: 1.0 diff --git a/param/perception/pc_filter_transform_rear_sim.param.yaml b/param/perception/pc_filter_transform_rear_sim.param.yaml deleted file mode 100755 index 4c5f37a19..000000000 --- a/param/perception/pc_filter_transform_rear_sim.param.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# config/test.param.yaml ---- -lidar_rear: - point_cloud_filter_transform_node: - ros__parameters: - timeout_ms: 110 - pcl_size: 55000 - input_frame_id: "lidar_rear" - output_frame_id: "base_link" - init_timeout_ms: 5000 - expected_num_subscribers: 1 - expected_num_publishers: 1 - start_angle: 0.0 # radians - end_angle: 6.28 - min_radius: 3.0 # meters - max_radius: 150.0 - static_transformer: - quaternion: - x: 0.0 - y: 0.0 - z: 0.0 - w: 1.0 - translation: - x: 0.308 - y: -0.022 - z: 1.49 diff --git a/params.yaml b/params.yaml index 1898bc097..eb89db718 100755 --- a/params.yaml +++ b/params.yaml @@ -115,7 +115,7 @@ mapping: ros__parameters: # lio sam ## Topics - pointCloudTopic: "/lidar_front/velodyne_points" # Point cloud data + pointCloudTopic: "/lidar_right/velodyne_points" # Point cloud data imuTopic: "/sensors/zed/imu" # IMU data odomTopic: "odometry/imu" # IMU pre-preintegration odometry, same frequency as IMU gpsTopic: "/sensors/gnss/odometry" # GPS odometry topic from navsat, see module_navsat.launch file @@ -252,7 +252,7 @@ perception: view_width: 6.283185307179586 # The width, in radians, of the view to generate for the resulting pointcloud. Combined with view_direction, this allows the node to generate a pointcloud only for the given width, centered at the view_direction point. This can vastly reduce the CPU requirements of the node. Must be between 0 and 2Pi. Defaults to 2Pi. organize_cloud: True # Whether to organize the cloud by ring (True), or to use the order as it comes directly from the driver (False). Defaults to True. target_frame: "base_link" # The coordinate frame to apply to the generated point cloud header before publishing. If the empty string (the default), the frame is passed along from the driver packet. If this frame is different than the fixed_frame, a transformation to this coordinate frame is performed while creating the pointcloud. - fixed_frame: "lidar_front" # The fixed coordinate frame to transform the data from. + fixed_frame: "lidar_right" # The fixed coordinate frame to transform the data from. # lidar pointcloud rear calibration: "/home/main/navigator/data/VLP16db.yaml" # The path to the calibration file for the particular device. There are a set of default calibration files to start with in the "params" subdirectory in this package. Defaults to the empty string. @@ -262,21 +262,21 @@ perception: view_width: 6.283185307179586 # The width, in radians, of the view to generate for the resulting pointcloud. Combined with view_direction, this allows the node to generate a pointcloud only for the given width, centered at the view_direction point. This can vastly reduce the CPU requirements of the node. Must be between 0 and 2Pi. Defaults to 2Pi. organize_cloud: True # Whether to organize the cloud by ring (True), or to use the order as it comes directly from the driver (False). Defaults to True. target_frame: "base_link" # The coordinate frame to apply to the generated point cloud header before publishing. If the empty string (the default), the frame is passed along from the driver packet. If this frame is different than the fixed_frame, a transformation to this coordinate frame is performed while creating the pointcloud. - fixed_frame: "lidar_rear" # The fixed coordinate frame to transform the data from. + fixed_frame: "lidar_left" # The fixed coordinate frame to transform the data from. # lidar rear ip: "0.0.0.0" port: 2368 cloud_size: 55000 topic: "points_raw" # UdpDriverNode strictly expects to get the topic via `declare_parameter`. - frame_id: "lidar_rear" + frame_id: "lidar_left" timeout_ms: 10 rpm: 600 # pc filter transform front timeout_ms: 110 pcl_size: 55000 - input_frame_id: "lidar_front" + input_frame_id: "lidar_right" output_frame_id: "base_link" init_timeout_ms: 5000 expected_num_subscribers: 1 @@ -299,7 +299,7 @@ perception: # pc filter transform front timeout_ms: 110 pcl_size: 55000 - input_frame_id: "lidar_front" + input_frame_id: "lidar_right" output_frame_id: "base_link" init_timeout_ms: 5000 expected_num_subscribers: 1 @@ -322,7 +322,7 @@ perception: # pc filter transform rear timeout_ms: 110 pcl_size: 55000 - input_frame_id: "lidar_rear" + input_frame_id: "lidar_left" output_frame_id: "base_link" # Use URDF transform init_timeout_ms: 5000 expected_num_subscribers: 1 @@ -345,7 +345,7 @@ perception: # pc filter transform rear sim timeout_ms: 110 pcl_size: 55000 - input_frame_id: "lidar_rear" + input_frame_id: "lidar_left" output_frame_id: "base_link" init_timeout_ms: 5000 expected_num_subscribers: 1 diff --git a/plot_pts.py b/plot_pts.py deleted file mode 100644 index a51db5fa1..000000000 --- a/plot_pts.py +++ /dev/null @@ -1,31 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np -from tqdm import tqdm, trange - -shape_data = np.genfromtxt('shapes.csv', delimiter=',') -# shape_data = shape_data[shape_data[:, 3] == 278] - -# print(shape_data) - -# plt.fill() - -# for i in range(183): -# lane_pts = shape_data[shape_data[:, 0] == i] -# if (len(lane_pts) == 0): -# continue -# print(lane_pts) -# if lane_pts[0, 3] == 278: -# plt.fill(lane_pts[:, 1], lane_pts[:, 2], c='purple') -# else: -# plt.fill(lane_pts[:, 1], lane_pts[:, 2], c='gray') - -# plt.show() - -data = np.genfromtxt('grid.csv', delimiter=',') - -plt.imshow(data) - -# occupied = data[data[:, 2] == 1] -# plt.scatter(occupied[:, 0], occupied[:, 1]) - -plt.show() diff --git a/points.csv b/points.csv deleted file mode 100644 index e397818bf..000000000 --- a/points.csv +++ /dev/null @@ -1,13014 +0,0 @@ --99.0652,-71.1218 --95.1347,-27.376 --99.1347,-27.3823 --99.0652,-71.1218 --95.0652,-71.1154 --95.1347,-27.376 --99.1347,-27.3823 --95.1419,2.4466 --99.1419,2.4457 --99.1347,-27.3823 --95.1347,-27.376 --95.1419,2.4466 --99.1419,2.4457 --95.1468,24.3332 --99.1468,24.3323 --99.1419,2.4457 --95.1419,2.4466 --95.1468,24.3332 --99.3652,-71.1222 --99.1347,-27.3823 --99.4347,-27.3828 --99.3652,-71.1222 --99.0652,-71.1218 --99.1347,-27.3823 --99.4347,-27.3828 --99.1419,2.4457 --99.4419,2.44563 --99.4347,-27.3828 --99.1347,-27.3823 --99.1419,2.4457 --99.4419,2.44563 --99.1468,24.3323 --99.4468,24.3323 --99.4419,2.44563 --99.1419,2.4457 --99.1468,24.3323 --103.365,-71.1286 --99.4347,-27.3828 --103.435,-27.3892 --103.365,-71.1286 --99.3652,-71.1222 --99.4347,-27.3828 --103.435,-27.3892 --99.4419,2.44563 --103.442,2.44472 --103.435,-27.3892 --99.4347,-27.3828 --99.4419,2.44563 --103.442,2.44472 --99.4468,24.3323 --103.447,24.3313 --103.442,2.44472 --99.4419,2.44563 --99.4468,24.3323 --103.365,-71.1286 --103.435,-27.3892 --103.435,-27.3892 --103.365,-71.1286 --103.365,-71.1286 --103.435,-27.3892 --103.435,-27.3892 --103.442,2.44472 --103.442,2.44472 --103.435,-27.3892 --103.435,-27.3892 --103.442,2.44472 --103.442,2.44472 --103.447,24.3313 --103.447,24.3313 --103.442,2.44472 --103.442,2.44472 --103.447,24.3313 --103.365,-71.1286 --103.435,-27.3892 --107.435,-27.3955 --103.365,-71.1286 --107.435,-27.3955 --107.365,-71.1349 --103.435,-27.3892 --103.442,2.44472 --107.442,2.44382 --103.435,-27.3892 --107.442,2.44382 --107.435,-27.3955 --103.442,2.44472 --103.447,24.3313 --107.447,24.3304 --103.442,2.44472 --107.447,24.3304 --107.442,2.44382 --107.365,-71.1349 --107.435,-27.3955 --107.735,-27.396 --107.365,-71.1349 --107.735,-27.396 --107.665,-71.1354 --107.435,-27.3955 --107.442,2.44382 --107.742,2.44375 --107.435,-27.3955 --107.742,2.44375 --107.735,-27.396 --107.442,2.44382 --107.447,24.3304 --107.747,24.3304 --107.442,2.44382 --107.747,24.3304 --107.742,2.44375 --107.665,-71.1354 --107.735,-27.396 --111.735,-27.4023 --107.665,-71.1354 --111.735,-27.4023 --111.665,-71.1418 --107.735,-27.396 --107.742,2.44375 --111.742,2.44285 --107.735,-27.396 --111.742,2.44285 --111.735,-27.4023 --107.742,2.44375 --107.747,24.3304 --111.747,24.3295 --107.742,2.44375 --111.747,24.3295 --111.742,2.44285 --99.1509,42.3323 --95.1551,60.9148 --99.1551,60.9139 --99.1509,42.3323 --95.1509,42.3332 --95.1551,60.9148 --99.1551,60.9139 --95.1538,62.1312 --99.1538,62.1402 --99.1551,60.9139 --95.1551,60.9148 --95.1538,62.1312 --99.1538,62.1402 --95.0552,105.993 --99.0552,106.002 --99.1538,62.1402 --95.1538,62.1312 --95.0552,105.993 --99.4509,42.3323 --99.1551,60.9139 --99.4551,60.9138 --99.4509,42.3323 --99.1509,42.3323 --99.1551,60.9139 --99.4551,60.9138 --99.1538,62.1402 --99.4538,62.1409 --99.4551,60.9138 --99.1551,60.9139 --99.1538,62.1402 --99.4538,62.1409 --99.0552,106.002 --99.3552,106.002 --99.4538,62.1409 --99.1538,62.1402 --99.0552,106.002 --103.451,42.3313 --99.4551,60.9138 --103.455,60.9129 --103.451,42.3313 --99.4509,42.3323 --99.4551,60.9138 --103.455,60.9129 --99.4538,62.1409 --103.454,62.1499 --103.455,60.9129 --99.4551,60.9138 --99.4538,62.1409 --103.454,62.1499 --99.3552,106.002 --103.355,106.011 --103.454,62.1499 --99.4538,62.1409 --99.3552,106.002 --103.451,42.3313 --103.455,60.9129 --103.455,60.9129 --103.451,42.3313 --103.451,42.3313 --103.455,60.9129 --103.455,60.9129 --103.454,62.1499 --103.454,62.1499 --103.455,60.9129 --103.455,60.9129 --103.454,62.1499 --103.454,62.1499 --103.355,106.011 --103.355,106.011 --103.454,62.1499 --103.454,62.1499 --103.355,106.011 --103.451,42.3313 --103.455,60.9129 --107.455,60.912 --103.451,42.3313 --107.455,60.912 --107.451,42.3304 --103.455,60.9129 --103.454,62.1499 --107.454,62.1589 --103.455,60.9129 --107.454,62.1589 --107.455,60.912 --103.454,62.1499 --103.355,106.011 --107.355,106.02 --103.454,62.1499 --107.355,106.02 --107.454,62.1589 --107.451,42.3304 --107.455,60.912 --107.755,60.9119 --107.451,42.3304 --107.755,60.9119 --107.751,42.3304 --107.455,60.912 --107.454,62.1589 --107.754,62.1596 --107.455,60.912 --107.754,62.1596 --107.755,60.9119 --107.454,62.1589 --107.355,106.02 --107.655,106.021 --107.454,62.1589 --107.655,106.021 --107.754,62.1596 --107.751,42.3304 --107.755,60.9119 --111.755,60.911 --107.751,42.3304 --111.755,60.911 --111.751,42.3295 --107.755,60.9119 --107.754,62.1596 --111.754,62.1686 --107.755,60.9119 --111.754,62.1686 --111.755,60.911 --107.754,62.1596 --107.655,106.021 --111.655,106.03 --107.754,62.1596 --111.655,106.03 --111.754,62.1686 -84.5274,-11.083 -44.9898,-7.05899 -44.9874,-11.059 -84.5274,-11.083 -84.5298,-7.083 -44.9898,-7.05899 -84.5272,-11.383 -44.9874,-11.059 -44.9872,-11.359 -84.5272,-11.383 -84.5274,-11.083 -44.9874,-11.059 -84.5248,-15.383 -44.9872,-11.359 -44.9848,-15.359 -84.5248,-15.383 -84.5272,-11.383 -44.9872,-11.359 -84.5248,-15.383 -44.9848,-15.359 -44.9848,-15.359 -84.5248,-15.383 -84.5248,-15.383 -44.9848,-15.359 -84.5248,-15.383 -44.9848,-15.359 -44.9824,-19.359 -84.5248,-15.383 -44.9824,-19.359 -84.5224,-19.383 -84.5224,-19.383 -44.9824,-19.359 -44.9822,-19.659 -84.5224,-19.383 -44.9822,-19.659 -84.5222,-19.683 -84.5222,-19.683 -44.9822,-19.659 -44.9798,-23.659 -84.5222,-19.683 -44.9798,-23.659 -84.5197,-23.683 --54.1401,-24.3286 --50.1402,-23.2083 --54.1402,-23.2086 --54.1401,-24.3286 --50.1401,-24.3283 --50.1402,-23.2083 --54.1402,-23.2086 --50.1403,-22.1748 --54.1403,-22.1751 --54.1402,-23.2086 --50.1402,-23.2083 --50.1403,-22.1748 --54.1403,-22.1751 --50.1057,-21.7134 --54.0608,-21.116 --54.1403,-22.1751 --50.1403,-22.1748 --50.1057,-21.7134 --54.0608,-21.116 --50.0025,-21.2624 --53.824,-20.0807 --54.0608,-21.116 --50.1057,-21.7134 --50.0025,-21.2624 --53.824,-20.0807 --49.8331,-20.8319 --53.435,-19.0923 --53.824,-20.0807 --50.0025,-21.2624 --49.8331,-20.8319 --53.435,-19.0923 --49.6012,-20.4315 --52.9028,-18.1732 --53.435,-19.0923 --49.8331,-20.8319 --49.6012,-20.4315 --52.9028,-18.1732 --49.3296,-20.0892 --52.2793,-17.3875 --52.9028,-18.1732 --49.6012,-20.4315 --49.3296,-20.0892 --52.2793,-17.3875 --49.0463,-19.8247 --51.5323,-16.6911 --52.2793,-17.3875 --49.3296,-20.0892 --49.0463,-19.8247 --51.5323,-16.6911 --48.7264,-19.6102 --50.6814,-16.1205 --51.5323,-16.6911 --49.0463,-19.8247 --48.7264,-19.6102 --50.6814,-16.1205 --48.3764,-19.4494 --49.7504,-15.6928 --50.6814,-16.1205 --48.7264,-19.6102 --48.3764,-19.4494 --49.7504,-15.6928 --48.0052,-19.3465 --48.7632,-15.4189 --49.7504,-15.6928 --48.3764,-19.4494 --48.0052,-19.3465 --48.7632,-15.4189 --47.6224,-19.3039 --47.745,-15.3058 --48.7632,-15.4189 --48.0052,-19.3465 --47.6224,-19.3039 --47.745,-15.3058 --46.2476,-19.3036 --46.2452,-15.3036 --47.745,-15.3058 --47.6224,-19.3039 --46.2476,-19.3036 --46.2452,-15.3036 --43.2776,-19.3054 --43.2752,-15.3054 --46.2452,-15.3036 --46.2476,-19.3036 --43.2776,-19.3054 --54.1401,-24.3286 --54.1402,-23.2086 --54.1402,-23.2086 --54.1401,-24.3286 --54.1401,-24.3286 --54.1402,-23.2086 --54.1402,-23.2086 --54.1403,-22.1751 --54.1403,-22.1751 --54.1402,-23.2086 --54.1402,-23.2086 --54.1403,-22.1751 --54.1403,-22.1751 --54.0608,-21.116 --54.0608,-21.116 --54.1403,-22.1751 --54.1403,-22.1751 --54.0608,-21.116 --54.0608,-21.116 --53.824,-20.0807 --53.824,-20.0807 --54.0608,-21.116 --54.0608,-21.116 --53.824,-20.0807 --53.824,-20.0807 --53.435,-19.0923 --53.435,-19.0923 --53.824,-20.0807 --53.824,-20.0807 --53.435,-19.0923 --53.435,-19.0923 --52.9028,-18.1732 --52.9028,-18.1732 --53.435,-19.0923 --53.435,-19.0923 --52.9028,-18.1732 --52.9028,-18.1732 --52.2793,-17.3875 --52.2793,-17.3875 --52.9028,-18.1732 --52.9028,-18.1732 --52.2793,-17.3875 --52.2793,-17.3875 --51.5323,-16.6911 --51.5323,-16.6911 --52.2793,-17.3875 --52.2793,-17.3875 --51.5323,-16.6911 --51.5323,-16.6911 --50.6814,-16.1205 --50.6814,-16.1205 --51.5323,-16.6911 --51.5323,-16.6911 --50.6814,-16.1205 --50.6814,-16.1205 --49.7504,-15.6928 --49.7504,-15.6928 --50.6814,-16.1205 --50.6814,-16.1205 --49.7504,-15.6928 --49.7504,-15.6928 --48.7632,-15.4189 --48.7632,-15.4189 --49.7504,-15.6928 --49.7504,-15.6928 --48.7632,-15.4189 --48.7632,-15.4189 --47.745,-15.3058 --47.745,-15.3058 --48.7632,-15.4189 --48.7632,-15.4189 --47.745,-15.3058 --47.745,-15.3058 --46.2452,-15.3036 --46.2452,-15.3036 --47.745,-15.3058 --47.745,-15.3058 --46.2452,-15.3036 --46.2452,-15.3036 --43.2752,-15.3054 --43.2752,-15.3054 --46.2452,-15.3036 --46.2452,-15.3036 --43.2752,-15.3054 -26.9874,-11.0481 --43.2701,-7.0054 --43.2726,-11.0054 -26.9874,-11.0481 -26.9898,-7.04806 --43.2701,-7.0054 -26.9872,-11.3481 --43.2726,-11.0054 --43.2728,-11.3054 -26.9872,-11.3481 -26.9874,-11.0481 --43.2726,-11.0054 -26.9848,-15.3481 --43.2728,-11.3054 --43.2752,-15.3054 -26.9848,-15.3481 -26.9872,-11.3481 --43.2728,-11.3054 -26.9848,-15.3481 --43.2752,-15.3054 --43.2752,-15.3054 -26.9848,-15.3481 -26.9848,-15.3481 --43.2752,-15.3054 -26.9848,-15.3481 --43.2752,-15.3054 --43.2776,-19.3054 -26.9848,-15.3481 --43.2776,-19.3054 -26.9824,-19.3481 -26.9824,-19.3481 --43.2776,-19.3054 --43.2778,-19.6054 -26.9824,-19.3481 --43.2778,-19.6054 -26.9822,-19.6481 -26.9822,-19.6481 --43.2778,-19.6054 --43.2802,-23.6054 -26.9822,-19.6481 --43.2802,-23.6054 -26.9798,-23.6481 --45.8401,-24.3279 --45.8259,-24.1924 --45.8259,-24.1924 --45.8401,-24.3279 --45.8401,-24.3279 --45.8259,-24.1924 --45.8259,-24.1924 --45.7837,-24.0629 --45.7837,-24.0629 --45.8259,-24.1924 --45.8259,-24.1924 --45.7837,-24.0629 --45.7837,-24.0629 --45.7154,-23.945 --45.7154,-23.945 --45.7837,-24.0629 --45.7837,-24.0629 --45.7154,-23.945 --45.7154,-23.945 --45.4765,-23.6851 --45.4765,-23.6851 --45.7154,-23.945 --45.7154,-23.945 --45.4765,-23.6851 --45.4765,-23.6851 --45.4287,-23.6471 --45.4287,-23.6471 --45.4765,-23.6851 --45.4765,-23.6851 --45.4287,-23.6471 --45.4287,-23.6471 --45.3738,-23.6204 --45.3738,-23.6204 --45.4287,-23.6471 --45.4287,-23.6471 --45.3738,-23.6204 --45.3738,-23.6204 --45.3144,-23.6063 --45.3144,-23.6063 --45.3738,-23.6204 --45.3738,-23.6204 --45.3144,-23.6063 --45.3144,-23.6063 --43.2802,-23.6054 --43.2802,-23.6054 --45.3144,-23.6063 --45.3144,-23.6063 --43.2802,-23.6054 --45.8401,-24.3279 --45.8259,-24.1924 --49.7381,-23.3589 --45.8401,-24.3279 --49.7381,-23.3589 --49.8401,-24.3282 --45.8259,-24.1924 --45.7837,-24.0629 --49.4362,-22.4322 --45.8259,-24.1924 --49.4362,-22.4322 --49.7381,-23.3589 --45.7837,-24.0629 --45.7154,-23.945 --48.9477,-21.5887 --45.7837,-24.0629 --48.9477,-21.5887 --49.4362,-22.4322 --45.7154,-23.945 --45.4765,-23.6851 --48.2974,-20.8492 --45.7154,-23.945 --48.2974,-20.8492 --48.9477,-21.5887 --45.4765,-23.6851 --45.4287,-23.6471 --47.5628,-20.2639 --45.4765,-23.6851 --47.5628,-20.2639 --48.2974,-20.8492 --45.4287,-23.6471 --45.3738,-23.6204 --46.7181,-19.853 --45.4287,-23.6471 --46.7181,-19.853 --47.5628,-20.2639 --45.3738,-23.6204 --45.3144,-23.6063 --45.8042,-19.6364 --45.3738,-23.6204 --45.8042,-19.6364 --46.7181,-19.853 --45.3144,-23.6063 --43.2802,-23.6054 --43.2778,-19.6054 --45.3144,-23.6063 --43.2778,-19.6054 --45.8042,-19.6364 --49.8401,-24.3282 --49.7381,-23.3589 --50.0315,-23.2964 --49.8401,-24.3282 --50.0315,-23.2964 --50.1401,-24.3283 --49.7381,-23.3589 --49.4362,-22.4322 --49.7101,-22.3099 --49.7381,-23.3589 --49.7101,-22.3099 --50.0315,-23.2964 --49.4362,-22.4322 --48.9477,-21.5887 --49.1902,-21.412 --49.4362,-22.4322 --49.1902,-21.412 --49.7101,-22.3099 --48.9477,-21.5887 --48.2974,-20.8492 --48.509,-20.6365 --48.9477,-21.5887 --48.509,-20.6365 --49.1902,-21.412 --48.2974,-20.8492 --47.5628,-20.2639 --47.7228,-20.0101 --48.2974,-20.8492 --47.7228,-20.0101 --48.509,-20.6365 --47.5628,-20.2639 --46.7181,-19.853 --46.819,-19.5705 --47.5628,-20.2639 --46.819,-19.5705 --47.7228,-20.0101 --46.7181,-19.853 --45.8042,-19.6364 --45.8409,-19.3386 --46.7181,-19.853 --45.8409,-19.3386 --46.819,-19.5705 --45.8042,-19.6364 --43.2778,-19.6054 --43.2776,-19.3054 --45.8042,-19.6364 --43.2776,-19.3054 --45.8409,-19.3386 --43.2752,-15.3054 --45.2728,-11.3042 --45.2752,-15.3042 --43.2752,-15.3054 --43.2728,-11.3054 --45.2728,-11.3042 --45.2752,-15.3042 --47.9083,-11.3026 --47.9108,-15.3026 --45.2752,-15.3042 --45.2728,-11.3042 --47.9083,-11.3026 --47.9108,-15.3026 --48.2484,-11.2734 --48.9275,-15.2153 --47.9108,-15.3026 --47.9083,-11.3026 --48.2484,-11.2734 --48.9275,-15.2153 --48.5786,-11.1871 --49.9149,-14.9573 --48.9275,-15.2153 --48.2484,-11.2734 --48.5786,-11.1871 --49.9149,-14.9573 --48.8895,-11.0462 --50.8443,-14.536 --49.9149,-14.9573 --48.5786,-11.1871 --48.8895,-11.0462 --50.8443,-14.536 --49.172,-10.8547 --51.6891,-13.9635 --50.8443,-14.536 --48.8895,-11.0462 --49.172,-10.8547 --51.6891,-13.9635 --49.4327,-10.6017 --52.4457,-13.2326 --51.6891,-13.9635 --49.172,-10.8547 --49.4327,-10.6017 --52.4457,-13.2326 --49.6908,-10.2572 --53.0631,-12.4083 --52.4457,-13.2326 --49.4327,-10.6017 --49.6908,-10.2572 --53.0631,-12.4083 --49.8944,-9.87792 --53.5503,-11.5009 --53.0631,-12.4083 --49.6908,-10.2572 --49.8944,-9.87792 --53.5503,-11.5009 --50.0391,-9.47251 --53.8965,-10.531 --53.5503,-11.5009 --49.8944,-9.87792 --50.0391,-9.47251 --53.8965,-10.531 --50.1216,-9.05003 --54.0939,-9.52016 --53.8965,-10.531 --50.0391,-9.47251 --50.1216,-9.05003 --54.0939,-9.52016 --50.1415,-8.49827 --54.1415,-8.49862 --54.0939,-9.52016 --50.1216,-9.05003 --50.1415,-8.49827 --54.1415,-8.49862 --50.1417,-6.32827 --54.1417,-6.32862 --54.1415,-8.49862 --50.1415,-8.49827 --50.1417,-6.32827 --54.1417,-6.32862 --50.1419,-4.01827 --54.1419,-4.01862 --54.1417,-6.32862 --50.1417,-6.32827 --50.1419,-4.01827 --43.2752,-15.3054 --45.2752,-15.3042 --45.2752,-15.3042 --43.2752,-15.3054 --43.2752,-15.3054 --45.2752,-15.3042 --45.2752,-15.3042 --47.9108,-15.3026 --47.9108,-15.3026 --45.2752,-15.3042 --45.2752,-15.3042 --47.9108,-15.3026 --47.9108,-15.3026 --48.9275,-15.2153 --48.9275,-15.2153 --47.9108,-15.3026 --47.9108,-15.3026 --48.9275,-15.2153 --48.9275,-15.2153 --49.9149,-14.9573 --49.9149,-14.9573 --48.9275,-15.2153 --48.9275,-15.2153 --49.9149,-14.9573 --49.9149,-14.9573 --50.8443,-14.536 --50.8443,-14.536 --49.9149,-14.9573 --49.9149,-14.9573 --50.8443,-14.536 --50.8443,-14.536 --51.6891,-13.9635 --51.6891,-13.9635 --50.8443,-14.536 --50.8443,-14.536 --51.6891,-13.9635 --51.6891,-13.9635 --52.4457,-13.2326 --52.4457,-13.2326 --51.6891,-13.9635 --51.6891,-13.9635 --52.4457,-13.2326 --52.4457,-13.2326 --53.0631,-12.4083 --53.0631,-12.4083 --52.4457,-13.2326 --52.4457,-13.2326 --53.0631,-12.4083 --53.0631,-12.4083 --53.5503,-11.5009 --53.5503,-11.5009 --53.0631,-12.4083 --53.0631,-12.4083 --53.5503,-11.5009 --53.5503,-11.5009 --53.8965,-10.531 --53.8965,-10.531 --53.5503,-11.5009 --53.5503,-11.5009 --53.8965,-10.531 --53.8965,-10.531 --54.0939,-9.52016 --54.0939,-9.52016 --53.8965,-10.531 --53.8965,-10.531 --54.0939,-9.52016 --54.0939,-9.52016 --54.1415,-8.49862 --54.1415,-8.49862 --54.0939,-9.52016 --54.0939,-9.52016 --54.1415,-8.49862 --54.1415,-8.49862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1415,-8.49862 --54.1415,-8.49862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1419,-4.01862 --54.1419,-4.01862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1419,-4.01862 -83.5019,120.451 -39.669,124.422 -39.6717,120.422 -83.5019,120.451 -83.4991,124.451 -39.669,124.422 -39.6717,120.422 -10.0565,124.441 -10.0537,120.441 -39.6717,120.422 -39.669,124.422 -10.0565,124.441 -10.0537,120.441 --19.3656,124.461 --19.3683,120.461 -10.0537,120.441 -10.0565,124.441 --19.3656,124.461 --19.3683,120.461 --47.797,124.481 --47.7997,120.481 --19.3683,120.461 --19.3656,124.461 --47.797,124.481 --47.7997,120.481 --49.9777,124.477 --49.9633,120.477 --47.7997,120.481 --47.797,124.481 --49.9777,124.477 --49.9633,120.477 --93.2252,124.321 --93.2107,120.321 --49.9633,120.477 --49.9777,124.477 --93.2252,124.321 -83.5021,120.151 -39.6717,120.422 -39.6719,120.122 -83.5021,120.151 -83.5019,120.451 -39.6717,120.422 -39.6719,120.122 -10.0537,120.441 -10.0535,120.141 -39.6719,120.122 -39.6717,120.422 -10.0537,120.441 -10.0535,120.141 --19.3683,120.461 --19.3685,120.161 -10.0535,120.141 -10.0537,120.441 --19.3683,120.461 --19.3685,120.161 --47.7997,120.481 --47.7999,120.181 --19.3685,120.161 --19.3683,120.461 --47.7997,120.481 --47.7999,120.181 --49.9633,120.477 --49.9622,120.177 --47.7999,120.181 --47.7997,120.481 --49.9633,120.477 --49.9622,120.177 --93.2107,120.321 --93.2097,120.021 --49.9622,120.177 --49.9633,120.477 --93.2107,120.321 -83.5048,116.151 -39.6719,120.122 -39.6746,116.122 -83.5048,116.151 -83.5021,120.151 -39.6719,120.122 -39.6746,116.122 -10.0535,120.141 -10.0508,116.141 -39.6746,116.122 -39.6719,120.122 -10.0535,120.141 -10.0508,116.141 --19.3685,120.161 --19.3712,116.161 -10.0508,116.141 -10.0535,120.141 --19.3685,120.161 --19.3712,116.161 --47.7999,120.181 --47.8027,116.181 --19.3712,116.161 --19.3685,120.161 --47.7999,120.181 --47.8027,116.181 --49.9622,120.177 --49.9478,116.178 --47.8027,116.181 --47.7999,120.181 --49.9622,120.177 --49.9478,116.178 --93.2097,120.021 --93.1952,116.021 --49.9478,116.178 --49.9622,120.177 --93.2097,120.021 -83.5048,116.151 -39.6746,116.122 -39.6746,116.122 -83.5048,116.151 -83.5048,116.151 -39.6746,116.122 -39.6746,116.122 -10.0508,116.141 -10.0508,116.141 -39.6746,116.122 -39.6746,116.122 -10.0508,116.141 -10.0508,116.141 --19.3712,116.161 --19.3712,116.161 -10.0508,116.141 -10.0508,116.141 --19.3712,116.161 --19.3712,116.161 --47.8027,116.181 --47.8027,116.181 --19.3712,116.161 --19.3712,116.161 --47.8027,116.181 --47.8027,116.181 --49.9478,116.178 --49.9478,116.178 --47.8027,116.181 --47.8027,116.181 --49.9478,116.178 --49.9478,116.178 --93.1952,116.021 --93.1952,116.021 --49.9478,116.178 --49.9478,116.178 --93.1952,116.021 -83.5048,116.151 -39.6746,116.122 -39.6773,112.122 -83.5048,116.151 -39.6773,112.122 -83.5075,112.151 -39.6746,116.122 -10.0508,116.141 -10.0481,112.141 -39.6746,116.122 -10.0481,112.141 -39.6773,112.122 -10.0508,116.141 --19.3712,116.161 --19.3739,112.161 -10.0508,116.141 --19.3739,112.161 -10.0481,112.141 --19.3712,116.161 --47.8027,116.181 --47.8054,112.181 --19.3712,116.161 --47.8054,112.181 --19.3739,112.161 --47.8027,116.181 --49.9478,116.178 --49.9333,112.178 --47.8027,116.181 --49.9333,112.178 --47.8054,112.181 --49.9478,116.178 --93.1952,116.021 --93.1808,112.021 --49.9478,116.178 --93.1808,112.021 --49.9333,112.178 -83.5075,112.151 -39.6773,112.122 -39.6775,111.822 -83.5075,112.151 -39.6775,111.822 -83.5077,111.851 -39.6773,112.122 -10.0481,112.141 -10.0479,111.841 -39.6773,112.122 -10.0479,111.841 -39.6775,111.822 -10.0481,112.141 --19.3739,112.161 --19.3741,111.861 -10.0481,112.141 --19.3741,111.861 -10.0479,111.841 --19.3739,112.161 --47.8054,112.181 --47.8056,111.881 --19.3739,112.161 --47.8056,111.881 --19.3741,111.861 --47.8054,112.181 --49.9333,112.178 --49.9322,111.878 --47.8054,112.181 --49.9322,111.878 --47.8056,111.881 --49.9333,112.178 --93.1808,112.021 --93.1797,111.721 --49.9333,112.178 --93.1797,111.721 --49.9322,111.878 -83.5077,111.851 -39.6775,111.822 -39.6803,107.822 -83.5077,111.851 -39.6803,107.822 -83.5104,107.851 -39.6775,111.822 -10.0479,111.841 -10.0452,107.841 -39.6775,111.822 -10.0452,107.841 -39.6803,107.822 -10.0479,111.841 --19.3741,111.861 --19.3768,107.861 -10.0479,111.841 --19.3768,107.861 -10.0452,107.841 --19.3741,111.861 --47.8056,111.881 --47.8083,107.881 --19.3741,111.861 --47.8083,107.881 --19.3768,107.861 --47.8056,111.881 --49.9322,111.878 --49.9178,107.878 --47.8056,111.881 --49.9178,107.878 --47.8083,107.881 --49.9322,111.878 --93.1797,111.721 --93.1653,107.721 --49.9322,111.878 --93.1653,107.721 --49.9178,107.878 --49.8419,-4.01825 --50.1417,-6.32846 --49.8417,-6.32842 --49.8419,-4.01825 --50.1419,-4.01827 --50.1417,-6.32846 --49.8417,-6.32842 --50.0331,-7.35763 --49.7397,-7.29506 --49.8417,-6.32842 --50.1417,-6.32846 --50.0331,-7.35763 --49.7397,-7.29506 --49.7124,-8.34156 --49.4384,-8.2192 --49.7397,-7.29506 --50.0331,-7.35763 --49.7124,-8.34156 --49.4384,-8.2192 --49.1936,-9.23701 --48.9512,-9.06023 --49.4384,-8.2192 --49.7124,-8.34156 --49.1936,-9.23701 --48.9512,-9.06023 --48.5166,-10.006 --48.307,-9.79136 --48.9512,-9.06023 --49.1936,-9.23701 --48.5166,-10.006 --48.307,-9.79136 --47.728,-10.6227 --47.5702,-10.3676 --48.307,-9.79136 --48.5166,-10.006 --47.728,-10.6227 --47.5702,-10.3676 --46.8237,-11.0526 --46.7254,-10.7691 --47.5702,-10.3676 --47.728,-10.6227 --46.8237,-11.0526 --46.7254,-10.7691 --45.8474,-11.2747 --45.8134,-10.9766 --46.7254,-10.7691 --46.8237,-11.0526 --45.8474,-11.2747 --45.8134,-10.9766 --43.2728,-11.3054 --43.2726,-11.0054 --45.8134,-10.9766 --45.8474,-11.2747 --43.2728,-11.3054 --45.8419,-4.0179 --49.8417,-6.32842 --45.8417,-6.32792 --45.8419,-4.0179 --49.8419,-4.01825 --49.8417,-6.32842 --45.8417,-6.32792 --49.7397,-7.29506 --45.8277,-6.46073 --45.8417,-6.32792 --49.8417,-6.32842 --49.7397,-7.29506 --45.8277,-6.46073 --49.4384,-8.2192 --45.7863,-6.5877 --45.8277,-6.46073 --49.7397,-7.29506 --49.4384,-8.2192 --45.7863,-6.5877 --48.9512,-9.06023 --45.7193,-6.70325 --45.7863,-6.5877 --49.4384,-8.2192 --48.9512,-9.06023 --45.7193,-6.70325 --48.307,-9.79136 --45.5118,-6.93009 --45.7193,-6.70325 --48.9512,-9.06023 --48.307,-9.79136 --45.5118,-6.93009 --47.5702,-10.3676 --45.4668,-6.96528 --45.5118,-6.93009 --48.307,-9.79136 --47.5702,-10.3676 --45.4668,-6.96528 --46.7254,-10.7691 --45.4152,-6.9898 --45.4668,-6.96528 --47.5702,-10.3676 --46.7254,-10.7691 --45.4152,-6.9898 --45.8134,-10.9766 --45.3595,-7.00247 --45.4152,-6.9898 --46.7254,-10.7691 --45.8134,-10.9766 --45.3595,-7.00247 --43.2726,-11.0054 --43.2701,-7.0054 --45.3595,-7.00247 --45.8134,-10.9766 --43.2726,-11.0054 --45.8419,-4.0179 --45.8417,-6.32792 --45.8417,-6.32792 --45.8419,-4.0179 --45.8419,-4.0179 --45.8417,-6.32792 --45.8417,-6.32792 --45.8277,-6.46073 --45.8277,-6.46073 --45.8417,-6.32792 --45.8417,-6.32792 --45.8277,-6.46073 --45.8277,-6.46073 --45.7863,-6.5877 --45.7863,-6.5877 --45.8277,-6.46073 --45.8277,-6.46073 --45.7863,-6.5877 --45.7863,-6.5877 --45.7193,-6.70325 --45.7193,-6.70325 --45.7863,-6.5877 --45.7863,-6.5877 --45.7193,-6.70325 --45.7193,-6.70325 --45.5118,-6.93009 --45.5118,-6.93009 --45.7193,-6.70325 --45.7193,-6.70325 --45.5118,-6.93009 --45.5118,-6.93009 --45.4668,-6.96528 --45.4668,-6.96528 --45.5118,-6.93009 --45.5118,-6.93009 --45.4668,-6.96528 --45.4668,-6.96528 --45.4152,-6.9898 --45.4152,-6.9898 --45.4668,-6.96528 --45.4668,-6.96528 --45.4152,-6.9898 --45.4152,-6.9898 --45.3595,-7.00247 --45.3595,-7.00247 --45.4152,-6.9898 --45.4152,-6.9898 --45.3595,-7.00247 --45.3595,-7.00247 --43.2701,-7.0054 --43.2701,-7.0054 --45.3595,-7.00247 --45.3595,-7.00247 --43.2701,-7.0054 -97.9748,-71.0115 -102.005,-27.3818 -98.0046,-27.3791 -97.9748,-71.0115 -101.975,-71.0143 -102.005,-27.3818 -98.0046,-27.3791 -102.004,-24.7767 -98.0042,-24.7776 -98.0046,-27.3791 -102.005,-27.3818 -102.004,-24.7767 -97.6748,-71.0113 -98.0046,-27.3791 -97.7046,-27.3789 -97.6748,-71.0113 -97.9748,-71.0115 -98.0046,-27.3791 -97.7046,-27.3789 -98.0042,-24.7776 -97.7042,-24.7777 -97.7046,-27.3789 -98.0046,-27.3791 -98.0042,-24.7776 -93.6748,-71.0086 -97.7046,-27.3789 -93.7046,-27.3761 -93.6748,-71.0086 -97.6748,-71.0113 -97.7046,-27.3789 -93.7046,-27.3761 -97.7042,-24.7777 -93.7042,-24.7786 -93.7046,-27.3761 -97.7046,-27.3789 -97.7042,-24.7777 -93.6748,-71.0086 -93.7046,-27.3761 -93.7046,-27.3761 -93.6748,-71.0086 -93.6748,-71.0086 -93.7046,-27.3761 -93.7046,-27.3761 -93.7042,-24.7786 -93.7042,-24.7786 -93.7046,-27.3761 -93.7046,-27.3761 -93.7042,-24.7786 -93.6748,-71.0086 -93.7046,-27.3761 -89.7046,-27.3734 -93.6748,-71.0086 -89.7046,-27.3734 -89.6748,-71.0059 -93.7046,-27.3761 -93.7042,-24.7786 -89.7042,-24.7795 -93.7046,-27.3761 -89.7042,-24.7795 -89.7046,-27.3734 -89.6748,-71.0059 -89.7046,-27.3734 -89.4046,-27.3732 -89.6748,-71.0059 -89.4046,-27.3732 -89.3748,-71.0057 -89.7046,-27.3734 -89.7042,-24.7795 -89.4042,-24.7796 -89.7046,-27.3734 -89.4042,-24.7796 -89.4046,-27.3732 -89.3748,-71.0057 -89.4046,-27.3732 -85.4046,-27.3705 -89.3748,-71.0057 -85.4046,-27.3705 -85.3748,-71.0029 -89.4046,-27.3732 -89.4042,-24.7796 -85.4042,-24.7805 -89.4046,-27.3732 -85.4042,-24.7805 -85.4046,-27.3705 --43.2756,-15.3054 --44.2975,-15.2715 --44.2975,-15.2715 --43.2756,-15.3054 --43.2756,-15.3054 --44.2975,-15.2715 --44.2975,-15.2715 --45.3293,-15.1359 --45.3293,-15.1359 --44.2975,-15.2715 --44.2975,-15.2715 --45.3293,-15.1359 --45.3293,-15.1359 --46.3426,-14.898 --46.3426,-14.898 --45.3293,-15.1359 --45.3293,-15.1359 --46.3426,-14.898 --46.3426,-14.898 --47.3269,-14.5602 --47.3269,-14.5602 --46.3426,-14.898 --46.3426,-14.898 --47.3269,-14.5602 --47.3269,-14.5602 --48.2727,-14.1258 --48.2727,-14.1258 --47.3269,-14.5602 --47.3269,-14.5602 --48.2727,-14.1258 --48.2727,-14.1258 --49.1703,-13.5991 --49.1703,-13.5991 --48.2727,-14.1258 --48.2727,-14.1258 --49.1703,-13.5991 --49.1703,-13.5991 --50.0109,-12.9854 --50.0109,-12.9854 --49.1703,-13.5991 --49.1703,-13.5991 --50.0109,-12.9854 --50.0109,-12.9854 --50.7861,-12.2909 --50.7861,-12.2909 --50.0109,-12.9854 --50.0109,-12.9854 --50.7861,-12.2909 --50.7861,-12.2909 --51.5114,-11.4971 --51.5114,-11.4971 --50.7861,-12.2909 --50.7861,-12.2909 --51.5114,-11.4971 --51.5114,-11.4971 --52.131,-10.6781 --52.131,-10.6781 --51.5114,-11.4971 --51.5114,-11.4971 --52.131,-10.6781 --52.131,-10.6781 --52.6745,-9.8067 --52.6745,-9.8067 --52.131,-10.6781 --52.131,-10.6781 --52.6745,-9.8067 --52.6745,-9.8067 --53.1374,-8.88999 --53.1374,-8.88999 --52.6745,-9.8067 --52.6745,-9.8067 --53.1374,-8.88999 --53.1374,-8.88999 --53.5161,-7.93538 --53.5161,-7.93538 --53.1374,-8.88999 --53.1374,-8.88999 --53.5161,-7.93538 --53.5161,-7.93538 --53.8075,-6.95059 --53.8075,-6.95059 --53.5161,-7.93538 --53.5161,-7.93538 --53.8075,-6.95059 --53.8075,-6.95059 --54.0091,-5.94361 --54.0091,-5.94361 --53.8075,-6.95059 --53.8075,-6.95059 --54.0091,-5.94361 --54.0091,-5.94361 --54.1195,-4.92257 --54.1195,-4.92257 --54.0091,-5.94361 --54.0091,-5.94361 --54.1195,-4.92257 --54.1195,-4.92257 --54.1419,-4.01862 --54.1419,-4.01862 --54.1195,-4.92257 --54.1195,-4.92257 --54.1419,-4.01862 --43.2756,-15.3054 --44.2975,-15.2715 --44.6195,-19.2585 --43.2756,-15.3054 --44.6195,-19.2585 --43.278,-19.3054 --44.2975,-15.2715 --45.3293,-15.1359 --46.0479,-19.0709 --44.2975,-15.2715 --46.0479,-19.0709 --44.6195,-19.2585 --45.3293,-15.1359 --46.3426,-14.898 --47.4503,-18.7416 --45.3293,-15.1359 --47.4503,-18.7416 --46.0479,-19.0709 --46.3426,-14.898 --47.3269,-14.5602 --48.8129,-18.274 --46.3426,-14.898 --48.8129,-18.274 --47.4503,-18.7416 --47.3269,-14.5602 --48.2727,-14.1258 --50.122,-17.6726 --47.3269,-14.5602 --50.122,-17.6726 --48.8129,-18.274 --48.2727,-14.1258 --49.1703,-13.5991 --51.3645,-16.9436 --48.2727,-14.1258 --51.3645,-16.9436 --50.122,-17.6726 --49.1703,-13.5991 --50.0109,-12.9854 --52.528,-16.0942 --49.1703,-13.5991 --52.528,-16.0942 --51.3645,-16.9436 --50.0109,-12.9854 --50.7861,-12.2909 --53.6009,-15.1328 --50.0109,-12.9854 --53.6009,-15.1328 --52.528,-16.0942 --50.7861,-12.2909 --51.5114,-11.4971 --54.5896,-14.0514 --50.7861,-12.2909 --54.5896,-14.0514 --53.6009,-15.1328 --51.5114,-11.4971 --52.131,-10.6781 --55.4263,-12.9454 --51.5114,-11.4971 --55.4263,-12.9454 --54.5896,-14.0514 --52.131,-10.6781 --52.6745,-9.8067 --56.1602,-11.7687 --52.131,-10.6781 --56.1602,-11.7687 --55.4263,-12.9454 --52.6745,-9.8067 --53.1374,-8.88999 --56.7854,-10.5307 --52.6745,-9.8067 --56.7854,-10.5307 --56.1602,-11.7687 --53.1374,-8.88999 --53.5161,-7.93538 --57.2968,-9.24159 --53.1374,-8.88999 --57.2968,-9.24159 --56.7854,-10.5307 --53.5161,-7.93538 --53.8075,-6.95059 --57.6903,-7.91171 --53.5161,-7.93538 --57.6903,-7.91171 --57.2968,-9.24159 --53.8075,-6.95059 --54.0091,-5.94361 --57.9626,-6.55186 --53.8075,-6.95059 --57.9626,-6.55186 --57.6903,-7.91171 --54.0091,-5.94361 --54.1195,-4.92257 --58.1116,-5.17303 --54.0091,-5.94361 --58.1116,-5.17303 --57.9626,-6.55186 --54.1195,-4.92257 --54.1419,-4.01862 --58.1419,-4.01897 --54.1195,-4.92257 --58.1419,-4.01897 --58.1116,-5.17303 -27.8237,-6.6002 -27.8223,-6.61158 -27.8223,-6.61158 -27.8237,-6.6002 -27.8237,-6.6002 -27.8223,-6.61158 -27.8223,-6.61158 -27.8184,-6.62236 -27.8184,-6.62236 -27.8223,-6.61158 -27.8223,-6.61158 -27.8184,-6.62236 -27.8184,-6.62236 -27.8122,-6.63197 -27.8122,-6.63197 -27.8184,-6.62236 -27.8184,-6.62236 -27.8122,-6.63197 -27.8122,-6.63197 -27.5935,-6.82451 -27.5935,-6.82451 -27.8122,-6.63197 -27.8122,-6.63197 -27.5935,-6.82451 -27.5935,-6.82451 -27.4421,-6.93034 -27.4421,-6.93034 -27.5935,-6.82451 -27.5935,-6.82451 -27.4421,-6.93034 -27.4421,-6.93034 -27.2726,-7.00398 -27.2726,-7.00398 -27.4421,-6.93034 -27.4421,-6.93034 -27.2726,-7.00398 -27.2726,-7.00398 -27.0919,-7.04248 -27.0919,-7.04248 -27.2726,-7.00398 -27.2726,-7.00398 -27.0919,-7.04248 -27.0919,-7.04248 -26.9899,-7.04806 -26.9899,-7.04806 -27.0919,-7.04248 -27.0919,-7.04248 -26.9899,-7.04806 -27.8237,-6.6002 -27.8223,-6.61158 -31.7161,-7.52744 -27.8237,-6.6002 -31.7161,-7.52744 -31.8237,-6.60425 -27.8223,-6.61158 -27.8184,-6.62236 -31.4009,-8.40179 -27.8223,-6.61158 -31.4009,-8.40179 -31.7161,-7.52744 -27.8184,-6.62236 -27.8122,-6.63197 -30.8946,-9.18125 -27.8184,-6.62236 -30.8946,-9.18125 -31.4009,-8.40179 -27.8122,-6.63197 -27.5935,-6.82451 -30.2006,-9.8582 -27.8122,-6.63197 -30.2006,-9.8582 -30.8946,-9.18125 -27.5935,-6.82451 -27.4421,-6.93034 -29.3945,-10.4215 -27.5935,-6.82451 -29.3945,-10.4215 -30.2006,-9.8582 -27.4421,-6.93034 -27.2726,-7.00398 -28.4925,-10.8134 -27.4421,-6.93034 -28.4925,-10.8134 -29.3945,-10.4215 -27.2726,-7.00398 -27.0919,-7.04248 -27.5306,-11.0183 -27.2726,-7.00398 -27.5306,-11.0183 -28.4925,-10.8134 -27.0919,-7.04248 -26.9899,-7.04806 -26.9876,-11.0481 -27.0919,-7.04248 -26.9876,-11.0481 -27.5306,-11.0183 -31.8237,-6.60425 -31.7161,-7.52744 -32.0081,-7.59613 -31.8237,-6.60425 -32.0081,-7.59613 -32.1237,-6.60456 -31.7161,-7.52744 -31.4009,-8.40179 -31.6695,-8.53524 -31.7161,-7.52744 -31.6695,-8.53524 -32.0081,-7.59613 -31.4009,-8.40179 -30.8946,-9.18125 -31.1258,-9.37244 -31.4009,-8.40179 -31.1258,-9.37244 -31.6695,-8.53524 -30.8946,-9.18125 -30.2006,-9.8582 -30.3961,-10.0857 -30.8946,-9.18125 -30.3961,-10.0857 -31.1258,-9.37244 -30.2006,-9.8582 -29.3945,-10.4215 -29.5409,-10.6833 -30.2006,-9.8582 -29.5409,-10.6833 -30.3961,-10.0857 -29.3945,-10.4215 -28.4925,-10.8134 -28.584,-11.0991 -29.3945,-10.4215 -28.584,-11.0991 -29.5409,-10.6833 -28.4925,-10.8134 -27.5306,-11.0183 -27.5635,-11.3165 -28.4925,-10.8134 -27.5635,-11.3165 -28.584,-11.0991 -27.5306,-11.0183 -26.9876,-11.0481 -26.9874,-11.3481 -27.5306,-11.0183 -26.9874,-11.3481 -27.5635,-11.3165 -36.1237,-6.60861 -36.1221,-8.09861 -36.1221,-8.09861 -36.1237,-6.60861 -36.1237,-6.60861 -36.1221,-8.09861 -36.1221,-8.09861 -36.1199,-9.12244 -36.1199,-9.12244 -36.1221,-8.09861 -36.1221,-8.09861 -36.1199,-9.12244 -36.1199,-9.12244 -36.011,-10.146 -36.011,-10.146 -36.1199,-9.12244 -36.1199,-9.12244 -36.011,-10.146 -36.011,-10.146 -35.7304,-11.1364 -35.7304,-11.1364 -36.011,-10.146 -36.011,-10.146 -35.7304,-11.1364 -35.7304,-11.1364 -35.2864,-12.0651 -35.2864,-12.0651 -35.7304,-11.1364 -35.7304,-11.1364 -35.2864,-12.0651 -35.2864,-12.0651 -34.6917,-12.9053 -34.6917,-12.9053 -35.2864,-12.0651 -35.2864,-12.0651 -34.6917,-12.9053 -34.6917,-12.9053 -33.9576,-13.6378 -33.9576,-13.6378 -34.6917,-12.9053 -34.6917,-12.9053 -33.9576,-13.6378 -33.9576,-13.6378 -33.1417,-14.2357 -33.1417,-14.2357 -33.9576,-13.6378 -33.9576,-13.6378 -33.1417,-14.2357 -33.1417,-14.2357 -32.2503,-14.7139 -32.2503,-14.7139 -33.1417,-14.2357 -33.1417,-14.2357 -32.2503,-14.7139 -32.2503,-14.7139 -31.3008,-15.0631 -31.3008,-15.0631 -32.2503,-14.7139 -32.2503,-14.7139 -31.3008,-15.0631 -31.3008,-15.0631 -30.312,-15.2763 -30.312,-15.2763 -31.3008,-15.0631 -31.3008,-15.0631 -30.312,-15.2763 -30.312,-15.2763 -29.303,-15.3494 -29.303,-15.3494 -30.312,-15.2763 -30.312,-15.2763 -29.303,-15.3494 -29.303,-15.3494 -28.1148,-15.3487 -28.1148,-15.3487 -29.303,-15.3494 -29.303,-15.3494 -28.1148,-15.3487 -28.1148,-15.3487 -26.9848,-15.3481 -26.9848,-15.3481 -28.1148,-15.3487 -28.1148,-15.3487 -26.9848,-15.3481 -36.1237,-6.60861 -36.1221,-8.09861 -40.1221,-8.10266 -36.1237,-6.60861 -40.1221,-8.10266 -40.1237,-6.61266 -36.1221,-8.09861 -36.1199,-9.12244 -40.119,-9.20649 -36.1221,-8.09861 -40.119,-9.20649 -40.1221,-8.10266 -36.1199,-9.12244 -36.011,-10.146 -39.9382,-10.9054 -36.1199,-9.12244 -39.9382,-10.9054 -40.119,-9.20649 -36.011,-10.146 -35.7304,-11.1364 -39.4726,-12.5493 -36.011,-10.146 -39.4726,-12.5493 -39.9382,-10.9054 -35.7304,-11.1364 -35.2864,-12.0651 -38.7356,-14.0907 -35.7304,-11.1364 -38.7356,-14.0907 -39.4726,-12.5493 -35.2864,-12.0651 -34.6917,-12.9053 -37.7484,-15.4852 -35.2864,-12.0651 -37.7484,-15.4852 -38.7356,-14.0907 -34.6917,-12.9053 -33.9576,-13.6378 -36.5418,-16.6911 -34.6917,-12.9053 -36.5418,-16.6911 -37.7484,-15.4852 -33.9576,-13.6378 -33.1417,-14.2357 -35.2745,-17.6197 -33.9576,-13.6378 -35.2745,-17.6197 -36.5418,-16.6911 -33.1417,-14.2357 -32.2503,-14.7139 -33.89,-18.3624 -33.1417,-14.2357 -33.89,-18.3624 -35.2745,-17.6197 -32.2503,-14.7139 -31.3008,-15.0631 -32.4154,-18.9046 -32.2503,-14.7139 -32.4154,-18.9046 -33.89,-18.3624 -31.3008,-15.0631 -30.312,-15.2763 -30.8795,-19.2358 -31.3008,-15.0631 -30.8795,-19.2358 -32.4154,-18.9046 -30.312,-15.2763 -29.303,-15.3494 -29.3125,-19.3494 -30.312,-15.2763 -29.3125,-19.3494 -30.8795,-19.2358 -29.303,-15.3494 -28.1148,-15.3487 -28.1124,-19.3487 -29.303,-15.3494 -28.1124,-19.3487 -29.3125,-19.3494 -28.1148,-15.3487 -26.9848,-15.3481 -26.9824,-19.3481 -28.1148,-15.3487 -26.9824,-19.3481 -28.1124,-19.3487 -98.0002,-6.77764 -101.998,2.24575 -97.9981,2.24484 -98.0002,-6.77764 -102,-6.77673 -101.998,2.24575 -97.9981,2.24484 -101.993,24.4833 -97.9931,24.4824 -97.9981,2.24484 -101.998,2.24575 -101.993,24.4833 -97.7002,-6.77771 -97.9981,2.24484 -97.6981,2.24478 -97.7002,-6.77771 -98.0002,-6.77764 -97.9981,2.24484 -97.6981,2.24478 -97.9931,24.4824 -97.6931,24.4823 -97.6981,2.24478 -97.9981,2.24484 -97.9931,24.4824 -93.7002,-6.77861 -97.6981,2.24478 -93.6981,2.24387 -93.7002,-6.77861 -97.7002,-6.77771 -97.6981,2.24478 -93.6981,2.24387 -97.6931,24.4823 -93.6931,24.4814 -93.6981,2.24387 -97.6981,2.24478 -97.6931,24.4823 -93.7002,-6.77861 -93.6981,2.24387 -93.6981,2.24387 -93.7002,-6.77861 -93.7002,-6.77861 -93.6981,2.24387 -93.6981,2.24387 -93.6931,24.4814 -93.6931,24.4814 -93.6981,2.24387 -93.6981,2.24387 -93.6931,24.4814 -93.7002,-6.77861 -93.6981,2.24387 -89.6981,2.24297 -93.7002,-6.77861 -89.6981,2.24297 -89.7002,-6.77951 -93.6981,2.24387 -93.6931,24.4814 -89.6931,24.4805 -93.6981,2.24387 -89.6931,24.4805 -89.6981,2.24297 -89.7002,-6.77951 -89.6981,2.24297 -89.3981,2.2429 -89.7002,-6.77951 -89.3981,2.2429 -89.4002,-6.77958 -89.6981,2.24297 -89.6931,24.4805 -89.3931,24.4804 -89.6981,2.24297 -89.3931,24.4804 -89.3981,2.2429 -89.4002,-6.77958 -89.3981,2.2429 -85.3981,2.242 -89.4002,-6.77958 -85.3981,2.242 -85.4002,-6.78049 -89.3981,2.2429 -89.3931,24.4804 -85.3931,24.4795 -89.3981,2.2429 -85.3931,24.4795 -85.3981,2.242 -26.9848,-15.3481 -29.5932,-15.3496 -29.5932,-15.3496 -26.9848,-15.3481 -26.9848,-15.3481 -29.5932,-15.3496 -29.5932,-15.3496 -30.6407,-15.2663 -30.6407,-15.2663 -29.5932,-15.3496 -29.5932,-15.3496 -30.6407,-15.2663 -30.6407,-15.2663 -31.6616,-15.0171 -31.6616,-15.0171 -30.6407,-15.2663 -30.6407,-15.2663 -31.6616,-15.0171 -31.6616,-15.0171 -32.6297,-14.6085 -32.6297,-14.6085 -31.6616,-15.0171 -31.6616,-15.0171 -32.6297,-14.6085 -32.6297,-14.6085 -33.5204,-14.0509 -33.5204,-14.0509 -32.6297,-14.6085 -32.6297,-14.6085 -33.5204,-14.0509 -33.5204,-14.0509 -34.2901,-13.3796 -34.2901,-13.3796 -33.5204,-14.0509 -33.5204,-14.0509 -34.2901,-13.3796 -34.2901,-13.3796 -34.9461,-12.5934 -34.9461,-12.5934 -34.2901,-13.3796 -34.2901,-13.3796 -34.9461,-12.5934 -34.9461,-12.5934 -35.4685,-11.7128 -35.4685,-11.7128 -34.9461,-12.5934 -34.9461,-12.5934 -35.4685,-11.7128 -35.4685,-11.7128 -35.8439,-10.7602 -35.8439,-10.7602 -35.4685,-11.7128 -35.4685,-11.7128 -35.8439,-10.7602 -35.8439,-10.7602 -36.0627,-9.75997 -36.0627,-9.75997 -35.8439,-10.7602 -35.8439,-10.7602 -36.0627,-9.75997 -36.0627,-9.75997 -36.1221,-8.09861 -36.1221,-8.09861 -36.0627,-9.75997 -36.0627,-9.75997 -36.1221,-8.09861 -36.1221,-8.09861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1221,-8.09861 -36.1221,-8.09861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1237,-6.60861 -36.1237,-6.60861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1237,-6.60861 -26.9848,-15.3481 -29.5932,-15.3496 -29.5956,-11.3496 -26.9848,-15.3481 -29.5956,-11.3496 -26.9872,-11.3481 -29.5932,-15.3496 -30.6407,-15.2663 -30.0058,-11.317 -29.5932,-15.3496 -30.0058,-11.317 -29.5956,-11.3496 -30.6407,-15.2663 -31.6616,-15.0171 -30.4056,-11.2194 -30.6407,-15.2663 -30.4056,-11.2194 -30.0058,-11.317 -31.6616,-15.0171 -32.6297,-14.6085 -30.7847,-11.0594 -31.6616,-15.0171 -30.7847,-11.0594 -30.4056,-11.2194 -32.6297,-14.6085 -33.5204,-14.0509 -31.1335,-10.841 -32.6297,-14.6085 -31.1335,-10.841 -30.7847,-11.0594 -33.5204,-14.0509 -34.2901,-13.3796 -31.4335,-10.5796 -33.5204,-14.0509 -31.4335,-10.5796 -31.1335,-10.841 -34.2901,-13.3796 -34.9461,-12.5934 -31.6799,-10.2843 -34.2901,-13.3796 -31.6799,-10.2843 -31.4335,-10.5796 -34.9461,-12.5934 -35.4685,-11.7128 -31.8761,-9.95355 -34.9461,-12.5934 -31.8761,-9.95355 -31.6799,-10.2843 -35.4685,-11.7128 -35.8439,-10.7602 -32.0171,-9.59575 -35.4685,-11.7128 -32.0171,-9.59575 -31.8761,-9.95355 -35.8439,-10.7602 -36.0627,-9.75997 -32.0993,-9.22006 -35.8439,-10.7602 -32.0993,-9.22006 -32.0171,-9.59575 -36.0627,-9.75997 -36.1221,-8.09861 -32.1221,-8.09455 -36.0627,-9.75997 -32.1221,-8.09455 -32.0993,-9.22006 -36.1221,-8.09861 -36.1236,-6.61861 -32.1236,-6.61456 -36.1221,-8.09861 -32.1236,-6.61456 -32.1221,-8.09455 -36.1236,-6.61861 -36.1237,-6.60861 -32.1237,-6.60456 -36.1236,-6.61861 -32.1237,-6.60456 -32.1236,-6.61456 -40.4237,-6.61297 -40.2333,-7.62488 -40.5262,-7.55969 -40.4237,-6.61297 -40.1237,-6.61266 -40.2333,-7.62488 -40.5262,-7.55969 -40.559,-8.57882 -40.8306,-8.4513 -40.5262,-7.55969 -40.2333,-7.62488 -40.559,-8.57882 -40.8306,-8.4513 -41.0851,-9.43868 -41.3223,-9.25498 -40.8306,-8.4513 -40.559,-8.57882 -41.0851,-9.43868 -41.3223,-9.25498 -41.7801,-10.1646 -41.9762,-9.93758 -41.3223,-9.25498 -41.0851,-9.43868 -41.7801,-10.1646 -41.9762,-9.93758 -42.6254,-10.7521 -42.7699,-10.4892 -41.9762,-9.93758 -41.7801,-10.1646 -42.6254,-10.7521 -42.7699,-10.4892 -43.5746,-11.1506 -43.6611,-10.8633 -42.7699,-10.4892 -42.6254,-10.7521 -43.5746,-11.1506 -43.6611,-10.8633 -44.5861,-11.3423 -44.6107,-11.0434 -43.6611,-10.8633 -43.5746,-11.1506 -44.5861,-11.3423 -44.6107,-11.0434 -44.9872,-11.359 -44.9874,-11.059 -44.6107,-11.0434 -44.5861,-11.3423 -44.9872,-11.359 -44.4237,-6.61702 -40.5262,-7.55969 -44.4306,-6.69057 -44.4237,-6.61702 -40.4237,-6.61297 -40.5262,-7.55969 -44.4306,-6.69057 -40.8306,-8.4513 -44.4513,-6.75106 -44.4306,-6.69057 -40.5262,-7.55969 -40.8306,-8.4513 -44.4513,-6.75106 -41.3223,-9.25498 -44.4846,-6.80559 -44.4513,-6.75106 -40.8306,-8.4513 -41.3223,-9.25498 -44.4846,-6.80559 -41.9762,-9.93758 -44.5907,-6.91036 -44.4846,-6.80559 -41.3223,-9.25498 -41.9762,-9.93758 -44.5907,-6.91036 -42.7699,-10.4892 -44.6959,-6.98347 -44.5907,-6.91036 -41.9762,-9.93758 -42.7699,-10.4892 -44.6959,-6.98347 -43.6611,-10.8633 -44.814,-7.03305 -44.6959,-6.98347 -42.7699,-10.4892 -43.6611,-10.8633 -44.814,-7.03305 -44.6107,-11.0434 -44.9399,-7.05692 -44.814,-7.03305 -43.6611,-10.8633 -44.6107,-11.0434 -44.9399,-7.05692 -44.9874,-11.059 -44.9898,-7.05899 -44.9399,-7.05692 -44.6107,-11.0434 -44.9874,-11.059 -44.4237,-6.61702 -44.4306,-6.69057 -44.4306,-6.69057 -44.4237,-6.61702 -44.4237,-6.61702 -44.4306,-6.69057 -44.4306,-6.69057 -44.4513,-6.75106 -44.4513,-6.75106 -44.4306,-6.69057 -44.4306,-6.69057 -44.4513,-6.75106 -44.4513,-6.75106 -44.4846,-6.80559 -44.4846,-6.80559 -44.4513,-6.75106 -44.4513,-6.75106 -44.4846,-6.80559 -44.4846,-6.80559 -44.5907,-6.91036 -44.5907,-6.91036 -44.4846,-6.80559 -44.4846,-6.80559 -44.5907,-6.91036 -44.5907,-6.91036 -44.6959,-6.98347 -44.6959,-6.98347 -44.5907,-6.91036 -44.5907,-6.91036 -44.6959,-6.98347 -44.6959,-6.98347 -44.814,-7.03305 -44.814,-7.03305 -44.6959,-6.98347 -44.6959,-6.98347 -44.814,-7.03305 -44.814,-7.03305 -44.9399,-7.05692 -44.9399,-7.05692 -44.814,-7.03305 -44.814,-7.03305 -44.9399,-7.05692 -44.9399,-7.05692 -44.9898,-7.05899 -44.9898,-7.05899 -44.9399,-7.05692 -44.9399,-7.05692 -44.9898,-7.05899 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -44.9848,-15.359 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -42.1072,-15.3572 -42.1072,-15.3572 -43.8248,-15.3583 -43.8248,-15.3583 -42.1072,-15.3572 -42.1072,-15.3572 -41.1052,-15.2713 -41.1052,-15.2713 -42.1072,-15.3572 -42.1072,-15.3572 -41.1052,-15.2713 -41.1052,-15.2713 -40.1321,-15.017 -40.1321,-15.017 -41.1052,-15.2713 -41.1052,-15.2713 -40.1321,-15.017 -40.1321,-15.017 -39.2162,-14.6017 -39.2162,-14.6017 -40.1321,-15.017 -40.1321,-15.017 -39.2162,-14.6017 -39.2162,-14.6017 -38.3836,-14.0375 -38.3836,-14.0375 -39.2162,-14.6017 -39.2162,-14.6017 -38.3836,-14.0375 -38.3836,-14.0375 -37.6527,-13.3344 -37.6527,-13.3344 -38.3836,-14.0375 -38.3836,-14.0375 -37.6527,-13.3344 -37.6527,-13.3344 -37.0317,-12.4929 -37.0317,-12.4929 -37.6527,-13.3344 -37.6527,-13.3344 -37.0317,-12.4929 -37.0317,-12.4929 -36.5621,-11.5585 -36.5621,-11.5585 -37.0317,-12.4929 -37.0317,-12.4929 -36.5621,-11.5585 -36.5621,-11.5585 -36.2572,-10.5581 -36.2572,-10.5581 -36.5621,-11.5585 -36.5621,-11.5585 -36.2572,-10.5581 -36.2572,-10.5581 -36.1261,-9.52052 -36.1261,-9.52052 -36.2572,-10.5581 -36.2572,-10.5581 -36.1261,-9.52052 -36.1261,-9.52052 -36.1219,-8.36861 -36.1219,-8.36861 -36.1261,-9.52052 -36.1261,-9.52052 -36.1219,-8.36861 -36.1219,-8.36861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1219,-8.36861 -36.1219,-8.36861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1237,-6.60861 -36.1237,-6.60861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1237,-6.60861 -44.9848,-15.359 -43.8248,-15.3583 -43.8224,-19.3583 -44.9848,-15.359 -43.8224,-19.3583 -44.9824,-19.359 -43.8248,-15.3583 -42.1072,-15.3572 -42.1048,-19.3572 -43.8248,-15.3583 -42.1048,-19.3572 -43.8224,-19.3583 -42.1072,-15.3572 -41.1052,-15.2713 -40.426,-19.2132 -42.1072,-15.3572 -40.426,-19.2132 -42.1048,-19.3572 -41.1052,-15.2713 -40.1321,-15.017 -38.7959,-18.7872 -41.1052,-15.2713 -38.7959,-18.7872 -40.426,-19.2132 -40.1321,-15.017 -39.2162,-14.6017 -37.2613,-18.0915 -40.1321,-15.017 -37.2613,-18.0915 -38.7959,-18.7872 -39.2162,-14.6017 -38.3836,-14.0375 -35.8666,-17.1463 -39.2162,-14.6017 -35.8666,-17.1463 -37.2613,-18.0915 -38.3836,-14.0375 -37.6527,-13.3344 -34.6475,-15.9743 -38.3836,-14.0375 -34.6475,-15.9743 -35.8666,-17.1463 -37.6527,-13.3344 -37.0317,-12.4929 -33.6232,-14.5863 -37.6527,-13.3344 -33.6232,-14.5863 -34.6475,-15.9743 -37.0317,-12.4929 -36.5621,-11.5585 -32.8485,-13.045 -37.0317,-12.4929 -32.8485,-13.045 -33.6232,-14.5863 -36.5621,-11.5585 -36.2572,-10.5581 -32.3458,-11.3949 -36.5621,-11.5585 -32.3458,-11.3949 -32.8485,-13.045 -36.2572,-10.5581 -36.1261,-9.52052 -32.1294,-9.68349 -36.2572,-10.5581 -32.1294,-9.68349 -32.3458,-11.3949 -36.1261,-9.52052 -36.1219,-8.36861 -32.1219,-8.36455 -36.1261,-9.52052 -32.1219,-8.36455 -32.1294,-9.68349 -36.1219,-8.36861 -36.1236,-6.61861 -32.1236,-6.61456 -36.1219,-8.36861 -32.1236,-6.61456 -32.1219,-8.36455 -36.1236,-6.61861 -36.1237,-6.60861 -32.1237,-6.60456 -36.1236,-6.61861 -32.1237,-6.60456 -32.1236,-6.61456 -97.989,42.4824 -101.985,60.9372 -97.9849,60.9363 -97.989,42.4824 -101.989,42.4833 -101.985,60.9372 -97.9849,60.9363 -102.045,105.49 -98.0448,105.496 -97.9849,60.9363 -101.985,60.9372 -102.045,105.49 -97.689,42.4823 -97.9849,60.9363 -97.6849,60.9362 -97.689,42.4823 -97.989,42.4824 -97.9849,60.9363 -97.6849,60.9362 -98.0448,105.496 -97.7448,105.496 -97.6849,60.9362 -97.9849,60.9363 -98.0448,105.496 -93.689,42.4814 -97.6849,60.9362 -93.6849,60.9353 -93.689,42.4814 -97.689,42.4823 -97.6849,60.9362 -93.6849,60.9353 -97.7448,105.496 -93.7448,105.501 -93.6849,60.9353 -97.6849,60.9362 -97.7448,105.496 -93.689,42.4814 -93.6849,60.9353 -93.6849,60.9353 -93.689,42.4814 -93.689,42.4814 -93.6849,60.9353 -93.6849,60.9353 -93.7448,105.501 -93.7448,105.501 -93.6849,60.9353 -93.6849,60.9353 -93.7448,105.501 -93.689,42.4814 -93.6849,60.9353 -89.6849,60.9344 -93.689,42.4814 -89.6849,60.9344 -89.689,42.4805 -93.6849,60.9353 -93.7448,105.501 -89.7448,105.507 -93.6849,60.9353 -89.7448,105.507 -89.6849,60.9344 -89.689,42.4805 -89.6849,60.9344 -89.3849,60.9343 -89.689,42.4805 -89.3849,60.9343 -89.389,42.4804 -89.6849,60.9344 -89.7448,105.507 -89.4448,105.507 -89.6849,60.9344 -89.4448,105.507 -89.3849,60.9343 -89.389,42.4804 -89.3849,60.9343 -85.3849,60.9334 -89.389,42.4804 -85.3849,60.9334 -85.389,42.4795 -89.3849,60.9343 -89.4448,105.507 -85.4448,105.513 -89.3849,60.9343 -85.4448,105.513 -85.3849,60.9334 -44.9848,-15.359 -43.8272,-11.3583 -43.8248,-15.3583 -44.9848,-15.359 -44.9872,-11.359 -43.8272,-11.3583 -43.8248,-15.3583 -42.7306,-11.3576 -42.7282,-15.3576 -43.8248,-15.3583 -43.8272,-11.3583 -42.7306,-11.3576 -42.7282,-15.3576 -42.3122,-11.3238 -41.6725,-15.2723 -42.7282,-15.3576 -42.7306,-11.3576 -42.3122,-11.3238 -41.6725,-15.2723 -41.9044,-11.2238 -40.6439,-15.02 -41.6725,-15.2723 -42.3122,-11.3238 -41.9044,-11.2238 -40.6439,-15.02 -41.5179,-11.0601 -39.6686,-14.6069 -40.6439,-15.02 -41.9044,-11.2238 -41.5179,-11.0601 -39.6686,-14.6069 -41.1623,-10.8368 -38.7716,-14.0438 -39.6686,-14.6069 -41.5179,-11.0601 -41.1623,-10.8368 -38.7716,-14.0438 -40.8606,-10.5739 -38.0099,-13.3799 -38.7716,-14.0438 -41.1623,-10.8368 -40.8606,-10.5739 -38.0099,-13.3799 -40.5965,-10.2588 -37.3352,-12.5747 -38.0099,-13.3799 -40.8606,-10.5739 -40.5965,-10.2588 -37.3352,-12.5747 -40.386,-9.90558 -36.7974,-11.6724 -37.3352,-12.5747 -40.5965,-10.2588 -40.386,-9.90558 -36.7974,-11.6724 -40.2345,-9.52336 -36.4102,-10.6958 -36.7974,-11.6724 -40.386,-9.90558 -40.2345,-9.52336 -36.4102,-10.6958 -40.1457,-9.12188 -36.1835,-9.67011 -36.4102,-10.6958 -40.2345,-9.52336 -40.1457,-9.12188 -36.1835,-9.67011 -40.122,-8.25266 -36.122,-8.24861 -36.1835,-9.67011 -40.1457,-9.12188 -40.122,-8.25266 -36.122,-8.24861 -40.1236,-6.62266 -36.1236,-6.61861 -36.122,-8.24861 -40.122,-8.25266 -40.1236,-6.62266 -36.1236,-6.61861 -40.1237,-6.61266 -36.1237,-6.60861 -36.1236,-6.61861 -40.1236,-6.62266 -40.1237,-6.61266 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -44.9848,-15.359 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -42.7282,-15.3576 -42.7282,-15.3576 -43.8248,-15.3583 -43.8248,-15.3583 -42.7282,-15.3576 -42.7282,-15.3576 -41.6725,-15.2723 -41.6725,-15.2723 -42.7282,-15.3576 -42.7282,-15.3576 -41.6725,-15.2723 -41.6725,-15.2723 -40.6439,-15.02 -40.6439,-15.02 -41.6725,-15.2723 -41.6725,-15.2723 -40.6439,-15.02 -40.6439,-15.02 -39.6686,-14.6069 -39.6686,-14.6069 -40.6439,-15.02 -40.6439,-15.02 -39.6686,-14.6069 -39.6686,-14.6069 -38.7716,-14.0438 -38.7716,-14.0438 -39.6686,-14.6069 -39.6686,-14.6069 -38.7716,-14.0438 -38.7716,-14.0438 -38.0099,-13.3799 -38.0099,-13.3799 -38.7716,-14.0438 -38.7716,-14.0438 -38.0099,-13.3799 -38.0099,-13.3799 -37.3352,-12.5747 -37.3352,-12.5747 -38.0099,-13.3799 -38.0099,-13.3799 -37.3352,-12.5747 -37.3352,-12.5747 -36.7974,-11.6724 -36.7974,-11.6724 -37.3352,-12.5747 -37.3352,-12.5747 -36.7974,-11.6724 -36.7974,-11.6724 -36.4102,-10.6958 -36.4102,-10.6958 -36.7974,-11.6724 -36.7974,-11.6724 -36.4102,-10.6958 -36.4102,-10.6958 -36.1835,-9.67011 -36.1835,-9.67011 -36.4102,-10.6958 -36.4102,-10.6958 -36.1835,-9.67011 -36.1835,-9.67011 -36.122,-8.24861 -36.122,-8.24861 -36.1835,-9.67011 -36.1835,-9.67011 -36.122,-8.24861 -36.122,-8.24861 -36.1236,-6.61861 -36.1236,-6.61861 -36.122,-8.24861 -36.122,-8.24861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1237,-6.60861 -36.1237,-6.60861 -36.1236,-6.61861 -36.1236,-6.61861 -36.1237,-6.60861 --99.0552,106.002 --95.053,106.997 --99.053,107.006 --99.0552,106.002 --95.0552,105.993 --95.053,106.997 --99.053,107.006 --95.0538,106.984 --99.0189,107.512 --99.053,107.006 --95.053,106.997 --95.0538,106.984 --99.0189,107.512 --95.0563,106.972 --98.9195,108.009 --99.0189,107.512 --95.0538,106.984 --95.0563,106.972 --98.9195,108.009 --95.0603,106.96 --98.7566,108.489 --98.9195,108.009 --95.0563,106.972 --95.0603,106.96 --98.7566,108.489 --95.0659,106.949 --98.5327,108.944 --98.7566,108.489 --95.0603,106.96 --95.0659,106.949 --98.5327,108.944 --95.0729,106.938 --98.2518,109.366 --98.5327,108.944 --95.0659,106.949 --95.0729,106.938 --98.2518,109.366 --95.0812,106.929 --97.9185,109.748 --98.2518,109.366 --95.0729,106.938 --95.0812,106.929 --97.9185,109.748 --95.0906,106.92 --97.5385,110.084 --97.9185,109.748 --95.0812,106.929 --95.0906,106.92 --97.5385,110.084 --94.6346,107.26 --96.9081,110.551 --97.5385,110.084 --95.0906,106.92 --94.6346,107.26 --96.9081,110.551 --94.4135,107.397 --96.3472,110.899 --96.9081,110.551 --94.6346,107.26 --94.4135,107.397 --96.3472,110.899 --94.1799,107.511 --95.7543,111.189 --96.3472,110.899 --94.4135,107.397 --94.1799,107.511 --95.7543,111.189 --93.936,107.602 --95.1354,111.418 --95.7543,111.189 --94.1799,107.511 --93.936,107.602 --95.1354,111.418 --93.6843,107.667 --94.4968,111.584 --95.1354,111.418 --93.936,107.602 --93.6843,107.667 --94.4968,111.584 --93.4274,107.707 --93.8448,111.685 --94.4968,111.584 --93.6843,107.667 --93.4274,107.707 --93.8448,111.685 --93.1677,107.721 --93.1859,111.721 --93.8448,111.685 --93.4274,107.707 --93.1677,107.721 --93.1859,111.721 --93.1653,107.721 --93.1799,111.721 --93.1859,111.721 --93.1677,107.721 --93.1653,107.721 --99.3552,106.002 --99.053,107.006 --99.353,107.006 --99.3552,106.002 --99.0552,106.002 --99.053,107.006 --99.353,107.006 --99.0189,107.512 --99.3163,107.551 --99.353,107.006 --99.053,107.006 --99.0189,107.512 --99.3163,107.551 --98.9195,108.009 --99.2093,108.087 --99.3163,107.551 --99.0189,107.512 --98.9195,108.009 --99.2093,108.087 --98.7566,108.489 --99.0338,108.604 --99.2093,108.087 --98.9195,108.009 --98.7566,108.489 --99.0338,108.604 --98.5327,108.944 --98.7927,109.094 --99.0338,108.604 --98.7566,108.489 --98.5327,108.944 --98.7927,109.094 --98.2518,109.366 --98.4902,109.548 --98.7927,109.094 --98.5327,108.944 --98.2518,109.366 --98.4902,109.548 --97.9185,109.748 --98.1313,109.96 --98.4902,109.548 --98.2518,109.366 --97.9185,109.748 --98.1313,109.96 --97.5385,110.084 --97.7221,110.321 --98.1313,109.96 --97.9185,109.748 --97.5385,110.084 --97.7221,110.321 --96.9081,110.551 --97.0787,110.798 --97.7221,110.321 --97.5385,110.084 --96.9081,110.551 --97.0787,110.798 --96.3472,110.899 --96.4922,111.161 --97.0787,110.798 --96.9081,110.551 --96.3472,110.899 --96.4922,111.161 --95.7543,111.189 --95.8724,111.464 --96.4922,111.161 --96.3472,110.899 --95.7543,111.189 --95.8724,111.464 --95.1354,111.418 --95.2254,111.704 --95.8724,111.464 --95.7543,111.189 --95.1354,111.418 --95.2254,111.704 --94.4968,111.584 --94.5577,111.878 --95.2254,111.704 --95.1354,111.418 --94.4968,111.584 --94.5577,111.878 --93.8448,111.685 --93.8761,111.984 --94.5577,111.878 --94.4968,111.584 --93.8448,111.685 --93.8761,111.984 --93.1859,111.721 --93.1872,112.021 --93.8761,111.984 --93.8448,111.685 --93.1859,111.721 --93.1872,112.021 --93.1799,111.721 --93.181,112.021 --93.1872,112.021 --93.1859,111.721 --93.1799,111.721 --103.355,106.011 --99.353,107.006 --103.353,107.015 --103.355,106.011 --99.3552,106.002 --99.353,107.006 --103.353,107.015 --99.3163,107.551 --103.281,108.079 --103.353,107.015 --99.353,107.006 --99.3163,107.551 --103.281,108.079 --99.2093,108.087 --103.073,109.124 --103.281,108.079 --99.3163,107.551 --99.2093,108.087 --103.073,109.124 --99.0338,108.604 --102.73,110.133 --103.073,109.124 --99.2093,108.087 --99.0338,108.604 --102.73,110.133 --98.7927,109.094 --102.26,111.089 --102.73,110.133 --99.0338,108.604 --98.7927,109.094 --102.26,111.089 --98.4902,109.548 --101.669,111.976 --102.26,111.089 --98.7927,109.094 --98.4902,109.548 --101.669,111.976 --98.1313,109.96 --100.969,112.779 --101.669,111.976 --98.4902,109.548 --98.1313,109.96 --100.969,112.779 --97.7221,110.321 --100.17,113.485 --100.969,112.779 --98.1313,109.96 --97.7221,110.321 --100.17,113.485 --97.0787,110.798 --99.3522,114.089 --100.17,113.485 --97.7221,110.321 --97.0787,110.798 --99.3522,114.089 --96.4922,111.161 --98.4258,114.663 --99.3522,114.089 --97.0787,110.798 --96.4922,111.161 --98.4258,114.663 --95.8724,111.464 --97.4468,115.141 --98.4258,114.663 --96.4922,111.161 --95.8724,111.464 --97.4468,115.141 --95.2254,111.704 --96.4248,115.52 --97.4468,115.141 --95.8724,111.464 --95.2254,111.704 --96.4248,115.52 --94.5577,111.878 --95.3702,115.794 --96.4248,115.52 --95.2254,111.704 --94.5577,111.878 --95.3702,115.794 --93.8761,111.984 --94.2935,115.962 --95.3702,115.794 --94.5577,111.878 --93.8761,111.984 --94.2935,115.962 --93.1872,112.021 --93.2054,116.021 --94.2935,115.962 --93.8761,111.984 --93.1872,112.021 --93.2054,116.021 --93.181,112.021 --93.1956,116.021 --93.2054,116.021 --93.1872,112.021 --93.181,112.021 --103.355,106.011 --103.353,107.015 --103.353,107.015 --103.355,106.011 --103.355,106.011 --103.353,107.015 --103.353,107.015 --103.281,108.079 --103.281,108.079 --103.353,107.015 --103.353,107.015 --103.281,108.079 --103.281,108.079 --103.073,109.124 --103.073,109.124 --103.281,108.079 --103.281,108.079 --103.073,109.124 --103.073,109.124 --102.73,110.133 --102.73,110.133 --103.073,109.124 --103.073,109.124 --102.73,110.133 --102.73,110.133 --102.26,111.089 --102.26,111.089 --102.73,110.133 --102.73,110.133 --102.26,111.089 --102.26,111.089 --101.669,111.976 --101.669,111.976 --102.26,111.089 --102.26,111.089 --101.669,111.976 --101.669,111.976 --100.969,112.779 --100.969,112.779 --101.669,111.976 --101.669,111.976 --100.969,112.779 --100.969,112.779 --100.17,113.485 --100.17,113.485 --100.969,112.779 --100.969,112.779 --100.17,113.485 --100.17,113.485 --99.3522,114.089 --99.3522,114.089 --100.17,113.485 --100.17,113.485 --99.3522,114.089 --99.3522,114.089 --98.4258,114.663 --98.4258,114.663 --99.3522,114.089 --99.3522,114.089 --98.4258,114.663 --98.4258,114.663 --97.4468,115.141 --97.4468,115.141 --98.4258,114.663 --98.4258,114.663 --97.4468,115.141 --97.4468,115.141 --96.4248,115.52 --96.4248,115.52 --97.4468,115.141 --97.4468,115.141 --96.4248,115.52 --96.4248,115.52 --95.3702,115.794 --95.3702,115.794 --96.4248,115.52 --96.4248,115.52 --95.3702,115.794 --95.3702,115.794 --94.2935,115.962 --94.2935,115.962 --95.3702,115.794 --95.3702,115.794 --94.2935,115.962 --94.2935,115.962 --93.2054,116.021 --93.2054,116.021 --94.2935,115.962 --94.2935,115.962 --93.2054,116.021 --93.2054,116.021 --93.1956,116.021 --93.1956,116.021 --93.2054,116.021 --93.2054,116.021 --93.1956,116.021 --103.355,106.011 --103.353,107.015 --107.353,107.024 --103.355,106.011 --107.353,107.024 --107.355,106.02 --103.353,107.015 --103.281,108.079 --107.246,108.606 --103.353,107.015 --107.246,108.606 --107.353,107.024 --103.281,108.079 --103.073,109.124 --106.936,110.161 --103.281,108.079 --106.936,110.161 --107.246,108.606 --103.073,109.124 --102.73,110.133 --106.426,111.662 --103.073,109.124 --106.426,111.662 --106.936,110.161 --102.73,110.133 --102.26,111.089 --105.726,113.084 --102.73,110.133 --105.726,113.084 --106.426,111.662 --102.26,111.089 --101.669,111.976 --104.848,114.404 --102.26,111.089 --104.848,114.404 --105.726,113.084 --101.669,111.976 --100.969,112.779 --103.806,115.599 --101.669,111.976 --103.806,115.599 --104.848,114.404 --100.969,112.779 --100.17,113.485 --102.618,116.648 --100.969,112.779 --102.618,116.648 --103.806,115.599 --100.17,113.485 --99.3522,114.089 --101.626,117.38 --100.17,113.485 --101.626,117.38 --102.618,116.648 --99.3522,114.089 --98.4258,114.663 --100.359,118.165 --99.3522,114.089 --100.359,118.165 --101.626,117.38 --98.4258,114.663 --97.4468,115.141 --99.0212,118.819 --98.4258,114.663 --99.0212,118.819 --100.359,118.165 --97.4468,115.141 --96.4248,115.52 --97.6243,119.336 --97.4468,115.141 --97.6243,119.336 --99.0212,118.819 --96.4248,115.52 --95.3702,115.794 --96.1827,119.711 --96.4248,115.52 --96.1827,119.711 --97.6243,119.336 --95.3702,115.794 --94.2935,115.962 --94.7109,119.94 --95.3702,115.794 --94.7109,119.94 --96.1827,119.711 --94.2935,115.962 --93.2054,116.021 --93.2236,120.021 --94.2935,115.962 --93.2236,120.021 --94.7109,119.94 --93.2054,116.021 --93.1956,116.021 --93.2102,120.021 --93.2054,116.021 --93.2102,120.021 --93.2236,120.021 --107.355,106.02 --107.353,107.024 --107.653,107.025 --107.355,106.02 --107.653,107.025 --107.655,106.021 --107.353,107.024 --107.246,108.606 --107.544,108.646 --107.353,107.024 --107.544,108.646 --107.653,107.025 --107.246,108.606 --106.936,110.161 --107.225,110.238 --107.246,108.606 --107.225,110.238 --107.544,108.646 --106.936,110.161 --106.426,111.662 --106.703,111.776 --106.936,110.161 --106.703,111.776 --107.225,110.238 --106.426,111.662 --105.726,113.084 --105.986,113.234 --106.426,111.662 --105.986,113.234 --106.703,111.776 --105.726,113.084 --104.848,114.404 --105.086,114.586 --105.726,113.084 --105.086,114.586 --105.986,113.234 --104.848,114.404 --103.806,115.599 --104.019,115.81 --104.848,114.404 --104.019,115.81 --105.086,114.586 --103.806,115.599 --102.618,116.648 --102.801,116.885 --103.806,115.599 --102.801,116.885 --104.019,115.81 --102.618,116.648 --101.626,117.38 --101.796,117.627 --102.618,116.648 --101.796,117.627 --102.801,116.885 --101.626,117.38 --100.359,118.165 --100.504,118.427 --101.626,117.38 --100.504,118.427 --101.796,117.627 --100.359,118.165 --99.0212,118.819 --99.1392,119.094 --100.359,118.165 --99.1392,119.094 --100.504,118.427 --99.0212,118.819 --97.6243,119.336 --97.7142,119.622 --99.0212,118.819 --97.7142,119.622 --99.1392,119.094 --97.6243,119.336 --96.1827,119.711 --96.2437,120.005 --97.6243,119.336 --96.2437,120.005 --97.7142,119.622 --96.1827,119.711 --94.7109,119.94 --94.7422,120.238 --96.1827,119.711 --94.7422,120.238 --96.2437,120.005 --94.7109,119.94 --93.2236,120.021 --93.225,120.321 --94.7109,119.94 --93.225,120.321 --94.7422,120.238 --93.2236,120.021 --93.2102,120.021 --93.2113,120.321 --93.2236,120.021 --93.2113,120.321 --93.225,120.321 --107.655,106.021 --107.653,107.025 --111.653,107.034 --107.655,106.021 --111.653,107.034 --111.655,106.03 --107.653,107.025 --107.544,108.646 --111.509,109.173 --107.653,107.025 --111.509,109.173 --111.653,107.034 --107.544,108.646 --107.225,110.238 --111.089,111.275 --107.544,108.646 --111.089,111.275 --111.509,109.173 --107.225,110.238 --106.703,111.776 --110.4,113.305 --107.225,110.238 --110.4,113.305 --111.089,111.275 --106.703,111.776 --105.986,113.234 --109.453,115.229 --106.703,111.776 --109.453,115.229 --110.4,113.305 --105.986,113.234 --105.086,114.586 --108.265,117.014 --105.986,113.234 --108.265,117.014 --109.453,115.229 --105.086,114.586 --104.019,115.81 --106.856,118.629 --105.086,114.586 --106.856,118.629 --108.265,117.014 --104.019,115.81 --102.801,116.885 --105.249,120.049 --104.019,115.81 --105.249,120.049 --106.856,118.629 --102.801,116.885 --101.796,117.627 --104.07,120.918 --102.801,116.885 --104.07,120.918 --105.249,120.049 --101.796,117.627 --100.504,118.427 --102.438,121.929 --101.796,117.627 --102.438,121.929 --104.07,120.918 --100.504,118.427 --99.1392,119.094 --100.714,122.772 --100.504,118.427 --100.714,122.772 --102.438,121.929 --99.1392,119.094 --97.7142,119.622 --98.9137,123.438 --99.1392,119.094 --98.9137,123.438 --100.714,122.772 --97.7142,119.622 --96.2437,120.005 --97.0562,123.921 --97.7142,119.622 --97.0562,123.921 --98.9137,123.438 --96.2437,120.005 --94.7422,120.238 --95.1597,124.217 --96.2437,120.005 --95.1597,124.217 --97.0562,123.921 --94.7422,120.238 --93.225,120.321 --93.2432,124.321 --94.7422,120.238 --93.2432,124.321 --95.1597,124.217 --93.225,120.321 --93.2113,120.321 --93.2258,124.321 --93.225,120.321 --93.2258,124.321 --93.2432,124.321 -89.3748,-71.0057 -85.3732,-71.3519 -89.3602,-71.6743 -89.3748,-71.0057 -85.3748,-71.0029 -85.3732,-71.3519 -89.3602,-71.6743 -85.3661,-71.4018 -89.2859,-72.1991 -89.3602,-71.6743 -85.3732,-71.3519 -85.3661,-71.4018 -89.2859,-72.1991 -85.3532,-71.4504 -89.1493,-72.7113 -89.2859,-72.1991 -85.3661,-71.4018 -85.3532,-71.4504 -89.1493,-72.7113 -85.3345,-71.4971 -88.9523,-73.2034 -89.1493,-72.7113 -85.3532,-71.4504 -85.3345,-71.4971 -88.9523,-73.2034 -85.3103,-71.5413 -88.6979,-73.6684 -88.9523,-73.2034 -85.3345,-71.4971 -85.3103,-71.5413 -88.6979,-73.6684 -85.281,-71.5822 -88.3896,-74.0995 -88.6979,-73.6684 -85.3103,-71.5413 -85.281,-71.5822 -88.3896,-74.0995 -85.2471,-71.6194 -88.0319,-74.4907 -88.3896,-74.0995 -85.281,-71.5822 -85.2471,-71.6194 -88.0319,-74.4907 -85.2089,-71.6522 -87.63,-74.8363 -88.0319,-74.4907 -85.2471,-71.6194 -85.2089,-71.6522 -87.63,-74.8363 -84.6652,-72.054 -86.9249,-75.3546 -87.63,-74.8363 -85.2089,-71.6522 -84.6652,-72.054 -86.9249,-75.3546 -84.414,-72.2099 -86.3679,-75.7002 -86.9249,-75.3546 -84.6652,-72.054 -84.414,-72.2099 -86.3679,-75.7002 -84.1498,-72.3426 -85.7821,-75.9944 -86.3679,-75.7002 -84.414,-72.2099 -84.1498,-72.3426 -85.7821,-75.9944 -83.8747,-72.451 -85.1722,-76.2347 -85.7821,-75.9944 -84.1498,-72.3426 -83.8747,-72.451 -85.1722,-76.2347 -83.591,-72.5342 -84.5432,-76.4192 -85.1722,-76.2347 -83.8747,-72.451 -83.591,-72.5342 -84.5432,-76.4192 -83.301,-72.5916 -83.9001,-76.5464 -84.5432,-76.4192 -83.591,-72.5342 -83.301,-72.5916 -83.9001,-76.5464 -83.007,-72.6226 -83.2482,-76.6154 -83.9001,-76.5464 -83.301,-72.5916 -83.007,-72.6226 -83.2482,-76.6154 -82.8135,-72.6286 -82.8191,-76.6286 -83.2482,-76.6154 -83.007,-72.6226 -82.8135,-72.6286 -89.6748,-71.0059 -89.3602,-71.6743 -89.6592,-71.6985 -89.6748,-71.0059 -89.3748,-71.0057 -89.3602,-71.6743 -89.6592,-71.6985 -89.2859,-72.1991 -89.5798,-72.2589 -89.6592,-71.6985 -89.3602,-71.6743 -89.2859,-72.1991 -89.5798,-72.2589 -89.1493,-72.7113 -89.434,-72.8058 -89.5798,-72.2589 -89.2859,-72.1991 -89.1493,-72.7113 -89.434,-72.8058 -88.9523,-73.2034 -89.2236,-73.3313 -89.434,-72.8058 -89.1493,-72.7113 -88.9523,-73.2034 -89.2236,-73.3313 -88.6979,-73.6684 -88.9519,-73.8279 -89.2236,-73.3313 -88.9523,-73.2034 -88.6979,-73.6684 -88.9519,-73.8279 -88.3896,-74.0995 -88.6227,-74.2883 -88.9519,-73.8279 -88.6979,-73.6684 -88.3896,-74.0995 -88.6227,-74.2883 -88.0319,-74.4907 -88.2408,-74.7061 -88.6227,-74.2883 -88.3896,-74.0995 -88.0319,-74.4907 -88.2408,-74.7061 -87.63,-74.8363 -87.8116,-75.0751 -88.2408,-74.7061 -88.0319,-74.4907 -87.63,-74.8363 -87.8116,-75.0751 -86.9249,-75.3546 -87.0944,-75.6022 -87.8116,-75.0751 -87.63,-74.8363 -86.9249,-75.3546 -87.0944,-75.6022 -86.3679,-75.7002 -86.5144,-75.962 -87.0944,-75.6022 -86.9249,-75.3546 -86.3679,-75.7002 -86.5144,-75.962 -85.7821,-75.9944 -85.9045,-76.2683 -86.5144,-75.962 -86.3679,-75.7002 -85.7821,-75.9944 -85.9045,-76.2683 -85.1722,-76.2347 -85.2695,-76.5185 -85.9045,-76.2683 -85.7821,-75.9944 -85.1722,-76.2347 -85.2695,-76.5185 -84.5432,-76.4192 -84.6146,-76.7106 -85.2695,-76.5185 -85.1722,-76.2347 -84.5432,-76.4192 -84.6146,-76.7106 -83.9001,-76.5464 -83.945,-76.8431 -84.6146,-76.7106 -84.5432,-76.4192 -83.9001,-76.5464 -83.945,-76.8431 -83.2482,-76.6154 -83.2663,-76.9148 -83.945,-76.8431 -83.9001,-76.5464 -83.2482,-76.6154 -83.2663,-76.9148 -82.8191,-76.6286 -82.8196,-76.9286 -83.2663,-76.9148 -83.2482,-76.6154 -82.8191,-76.6286 -93.6748,-71.0086 -89.6592,-71.6985 -93.6462,-72.0209 -93.6748,-71.0086 -89.6748,-71.0059 -89.6592,-71.6985 -93.6462,-72.0209 -89.5798,-72.2589 -93.4996,-73.0563 -93.6462,-72.0209 -89.6592,-71.6985 -89.5798,-72.2589 -93.4996,-73.0563 -89.434,-72.8058 -93.23,-74.0667 -93.4996,-73.0563 -89.5798,-72.2589 -89.434,-72.8058 -93.23,-74.0667 -89.2236,-73.3313 -92.8415,-75.0376 -93.23,-74.0667 -89.434,-72.8058 -89.2236,-73.3313 -92.8415,-75.0376 -88.9519,-73.8279 -92.3395,-75.955 -92.8415,-75.0376 -89.2236,-73.3313 -88.9519,-73.8279 -92.3395,-75.955 -88.6227,-74.2883 -91.7313,-76.8056 -92.3395,-75.955 -88.9519,-73.8279 -88.6227,-74.2883 -91.7313,-76.8056 -88.2408,-74.7061 -91.0257,-77.5774 -91.7313,-76.8056 -88.6227,-74.2883 -88.2408,-74.7061 -91.0257,-77.5774 -87.8116,-75.0751 -90.2327,-78.2591 -91.0257,-77.5774 -88.2408,-74.7061 -87.8116,-75.0751 -90.2327,-78.2591 -87.0944,-75.6022 -89.3541,-78.9027 -90.2327,-78.2591 -87.8116,-75.0751 -87.0944,-75.6022 -89.3541,-78.9027 -86.5144,-75.962 -88.4683,-79.4523 -89.3541,-78.9027 -87.0944,-75.6022 -86.5144,-75.962 -88.4683,-79.4523 -85.9045,-76.2683 -87.5368,-79.9201 -88.4683,-79.4523 -86.5144,-75.962 -85.9045,-76.2683 -87.5368,-79.9201 -85.2695,-76.5185 -86.5669,-80.3022 -87.5368,-79.9201 -85.9045,-76.2683 -85.2695,-76.5185 -86.5669,-80.3022 -84.6146,-76.7106 -85.5667,-80.5956 -86.5669,-80.3022 -85.2695,-76.5185 -84.6146,-76.7106 -85.5667,-80.5956 -83.945,-76.8431 -84.5441,-80.7979 -85.5667,-80.5956 -84.6146,-76.7106 -83.945,-76.8431 -84.5441,-80.7979 -83.2663,-76.9148 -83.5075,-80.9075 -84.5441,-80.7979 -83.945,-76.8431 -83.2663,-76.9148 -83.5075,-80.9075 -82.8196,-76.9286 -82.8252,-80.9286 -83.5075,-80.9075 -83.2663,-76.9148 -82.8196,-76.9286 -93.6748,-71.0086 -93.6462,-72.0209 -93.6462,-72.0209 -93.6748,-71.0086 -93.6748,-71.0086 -93.6462,-72.0209 -93.6462,-72.0209 -93.4996,-73.0563 -93.4996,-73.0563 -93.6462,-72.0209 -93.6462,-72.0209 -93.4996,-73.0563 -93.4996,-73.0563 -93.23,-74.0667 -93.23,-74.0667 -93.4996,-73.0563 -93.4996,-73.0563 -93.23,-74.0667 -93.23,-74.0667 -92.8415,-75.0376 -92.8415,-75.0376 -93.23,-74.0667 -93.23,-74.0667 -92.8415,-75.0376 -92.8415,-75.0376 -92.3395,-75.955 -92.3395,-75.955 -92.8415,-75.0376 -92.8415,-75.0376 -92.3395,-75.955 -92.3395,-75.955 -91.7313,-76.8056 -91.7313,-76.8056 -92.3395,-75.955 -92.3395,-75.955 -91.7313,-76.8056 -91.7313,-76.8056 -91.0257,-77.5774 -91.0257,-77.5774 -91.7313,-76.8056 -91.7313,-76.8056 -91.0257,-77.5774 -91.0257,-77.5774 -90.2327,-78.2591 -90.2327,-78.2591 -91.0257,-77.5774 -91.0257,-77.5774 -90.2327,-78.2591 -90.2327,-78.2591 -89.3541,-78.9027 -89.3541,-78.9027 -90.2327,-78.2591 -90.2327,-78.2591 -89.3541,-78.9027 -89.3541,-78.9027 -88.4683,-79.4523 -88.4683,-79.4523 -89.3541,-78.9027 -89.3541,-78.9027 -88.4683,-79.4523 -88.4683,-79.4523 -87.5368,-79.9201 -87.5368,-79.9201 -88.4683,-79.4523 -88.4683,-79.4523 -87.5368,-79.9201 -87.5368,-79.9201 -86.5669,-80.3022 -86.5669,-80.3022 -87.5368,-79.9201 -87.5368,-79.9201 -86.5669,-80.3022 -86.5669,-80.3022 -85.5667,-80.5956 -85.5667,-80.5956 -86.5669,-80.3022 -86.5669,-80.3022 -85.5667,-80.5956 -85.5667,-80.5956 -84.5441,-80.7979 -84.5441,-80.7979 -85.5667,-80.5956 -85.5667,-80.5956 -84.5441,-80.7979 -84.5441,-80.7979 -83.5075,-80.9075 -83.5075,-80.9075 -84.5441,-80.7979 -84.5441,-80.7979 -83.5075,-80.9075 -83.5075,-80.9075 -82.8252,-80.9286 -82.8252,-80.9286 -83.5075,-80.9075 -83.5075,-80.9075 -82.8252,-80.9286 -93.6748,-71.0086 -93.6462,-72.0209 -97.6332,-72.3433 -93.6748,-71.0086 -97.6332,-72.3433 -97.6748,-71.0113 -93.6462,-72.0209 -93.4996,-73.0563 -97.4193,-73.8536 -93.6462,-72.0209 -97.4193,-73.8536 -97.6332,-72.3433 -93.4996,-73.0563 -93.23,-74.0667 -97.0261,-75.3276 -93.4996,-73.0563 -97.0261,-75.3276 -97.4193,-73.8536 -93.23,-74.0667 -92.8415,-75.0376 -96.4593,-76.7438 -93.23,-74.0667 -96.4593,-76.7438 -97.0261,-75.3276 -92.8415,-75.0376 -92.3395,-75.955 -95.7271,-78.082 -92.8415,-75.0376 -95.7271,-78.082 -96.4593,-76.7438 -92.3395,-75.955 -91.7313,-76.8056 -94.8399,-79.3229 -92.3395,-75.955 -94.8399,-79.3229 -95.7271,-78.082 -91.7313,-76.8056 -91.0257,-77.5774 -93.8105,-80.4487 -91.7313,-76.8056 -93.8105,-80.4487 -94.8399,-79.3229 -91.0257,-77.5774 -90.2327,-78.2591 -92.6538,-81.4432 -91.0257,-77.5774 -92.6538,-81.4432 -93.8105,-80.4487 -90.2327,-78.2591 -89.3541,-78.9027 -91.6137,-82.2033 -90.2327,-78.2591 -91.6137,-82.2033 -92.6538,-81.4432 -89.3541,-78.9027 -88.4683,-79.4523 -90.4222,-82.9426 -89.3541,-78.9027 -90.4222,-82.9426 -91.6137,-82.2033 -88.4683,-79.4523 -87.5368,-79.9201 -89.169,-83.5719 -88.4683,-79.4523 -89.169,-83.5719 -90.4222,-82.9426 -87.5368,-79.9201 -86.5669,-80.3022 -87.8644,-84.0859 -87.5368,-79.9201 -87.8644,-84.0859 -89.169,-83.5719 -86.5669,-80.3022 -85.5667,-80.5956 -86.5188,-84.4806 -86.5669,-80.3022 -86.5188,-84.4806 -87.8644,-84.0859 -85.5667,-80.5956 -84.5441,-80.7979 -85.1432,-84.7528 -85.5667,-80.5956 -85.1432,-84.7528 -86.5188,-84.4806 -84.5441,-80.7979 -83.5075,-80.9075 -83.7487,-84.9003 -84.5441,-80.7979 -83.7487,-84.9003 -85.1432,-84.7528 -83.5075,-80.9075 -82.8252,-80.9286 -82.8308,-84.9286 -83.5075,-80.9075 -82.8308,-84.9286 -83.7487,-84.9003 -97.6748,-71.0113 -97.6332,-72.3433 -97.9322,-72.3674 -97.6748,-71.0113 -97.9322,-72.3674 -97.9748,-71.0115 -97.6332,-72.3433 -97.4193,-73.8536 -97.7133,-73.9134 -97.6332,-72.3433 -97.7133,-73.9134 -97.9322,-72.3674 -97.4193,-73.8536 -97.0261,-75.3276 -97.3108,-75.4221 -97.4193,-73.8536 -97.3108,-75.4221 -97.7133,-73.9134 -97.0261,-75.3276 -96.4593,-76.7438 -96.7307,-76.8718 -97.0261,-75.3276 -96.7307,-76.8718 -97.3108,-75.4221 -96.4593,-76.7438 -95.7271,-78.082 -95.9811,-78.2415 -96.4593,-76.7438 -95.9811,-78.2415 -96.7307,-76.8718 -95.7271,-78.082 -94.8399,-79.3229 -95.073,-79.5117 -95.7271,-78.082 -95.073,-79.5117 -95.9811,-78.2415 -94.8399,-79.3229 -93.8105,-80.4487 -94.0194,-80.6641 -94.8399,-79.3229 -94.0194,-80.6641 -95.073,-79.5117 -93.8105,-80.4487 -92.6538,-81.4432 -92.8354,-81.682 -93.8105,-80.4487 -92.8354,-81.682 -94.0194,-80.6641 -92.6538,-81.4432 -91.6137,-82.2033 -91.7832,-82.4509 -92.6538,-81.4432 -91.7832,-82.4509 -92.8354,-81.682 -91.6137,-82.2033 -90.4222,-82.9426 -90.5687,-83.2044 -91.6137,-82.2033 -90.5687,-83.2044 -91.7832,-82.4509 -90.4222,-82.9426 -89.169,-83.5719 -89.2915,-83.8458 -90.4222,-82.9426 -89.2915,-83.8458 -90.5687,-83.2044 -89.169,-83.5719 -87.8644,-84.0859 -87.9617,-84.3697 -89.169,-83.5719 -87.9617,-84.3697 -89.2915,-83.8458 -87.8644,-84.0859 -86.5188,-84.4806 -86.5902,-84.772 -87.8644,-84.0859 -86.5902,-84.772 -87.9617,-84.3697 -86.5188,-84.4806 -85.1432,-84.7528 -85.1881,-85.0494 -86.5188,-84.4806 -85.1881,-85.0494 -86.5902,-84.772 -85.1432,-84.7528 -83.7487,-84.9003 -83.7668,-85.1997 -85.1432,-84.7528 -83.7668,-85.1997 -85.1881,-85.0494 -83.7487,-84.9003 -82.8308,-84.9286 -82.8312,-85.2286 -83.7487,-84.9003 -82.8312,-85.2286 -83.7668,-85.1997 -97.9748,-71.0115 -97.9322,-72.3674 -101.919,-72.6898 -97.9748,-71.0115 -101.919,-72.6898 -101.975,-71.0143 -97.9322,-72.3674 -97.7133,-73.9134 -101.633,-74.7108 -97.9322,-72.3674 -101.633,-74.7108 -101.919,-72.6898 -97.7133,-73.9134 -97.3108,-75.4221 -101.107,-76.683 -97.7133,-73.9134 -101.107,-76.683 -101.633,-74.7108 -97.3108,-75.4221 -96.7307,-76.8718 -100.349,-78.578 -97.3108,-75.4221 -100.349,-78.578 -101.107,-76.683 -96.7307,-76.8718 -95.9811,-78.2415 -99.3687,-80.3686 -96.7307,-76.8718 -99.3687,-80.3686 -100.349,-78.578 -95.9811,-78.2415 -95.073,-79.5117 -98.1816,-82.029 -95.9811,-78.2415 -98.1816,-82.029 -99.3687,-80.3686 -95.073,-79.5117 -94.0194,-80.6641 -96.8042,-83.5354 -95.073,-79.5117 -96.8042,-83.5354 -98.1816,-82.029 -94.0194,-80.6641 -92.8354,-81.682 -95.2565,-84.8661 -94.0194,-80.6641 -95.2565,-84.8661 -96.8042,-83.5354 -92.8354,-81.682 -91.7832,-82.4509 -94.0429,-85.7514 -92.8354,-81.682 -94.0429,-85.7514 -95.2565,-84.8661 -91.7832,-82.4509 -90.5687,-83.2044 -92.5226,-86.6947 -91.7832,-82.4509 -92.5226,-86.6947 -94.0429,-85.7514 -90.5687,-83.2044 -89.2915,-83.8458 -90.9237,-87.4976 -90.5687,-83.2044 -90.9237,-87.4976 -92.5226,-86.6947 -89.2915,-83.8458 -87.9617,-84.3697 -89.2591,-88.1534 -89.2915,-83.8458 -89.2591,-88.1534 -90.9237,-87.4976 -87.9617,-84.3697 -86.5902,-84.772 -87.5423,-88.6571 -87.9617,-84.3697 -87.5423,-88.6571 -89.2591,-88.1534 -86.5902,-84.772 -85.1881,-85.0494 -85.7872,-89.0043 -86.5902,-84.772 -85.7872,-89.0043 -87.5423,-88.6571 -85.1881,-85.0494 -83.7668,-85.1997 -84.008,-89.1924 -85.1881,-85.0494 -84.008,-89.1924 -85.7872,-89.0043 -83.7668,-85.1997 -82.8312,-85.2286 -82.8369,-89.2286 -83.7668,-85.1997 -82.8369,-89.2286 -84.008,-89.1924 -44.9848,-15.359 -43.8272,-11.3583 -43.8248,-15.3583 -44.9848,-15.359 -44.9872,-11.359 -43.8272,-11.3583 -43.8248,-15.3583 -36.0572,-11.3536 -36.0548,-15.3536 -43.8248,-15.3583 -43.8272,-11.3583 -36.0572,-11.3536 -36.0548,-15.3536 -28.2672,-11.3488 -28.2648,-15.3488 -36.0548,-15.3536 -36.0572,-11.3536 -28.2672,-11.3488 -28.2648,-15.3488 -26.9872,-11.3481 -26.9848,-15.3481 -28.2648,-15.3488 -28.2672,-11.3488 -26.9872,-11.3481 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -44.9848,-15.359 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -36.0548,-15.3536 -36.0548,-15.3536 -43.8248,-15.3583 -43.8248,-15.3583 -36.0548,-15.3536 -36.0548,-15.3536 -28.2648,-15.3488 -28.2648,-15.3488 -36.0548,-15.3536 -36.0548,-15.3536 -28.2648,-15.3488 -28.2648,-15.3488 -26.9848,-15.3481 -26.9848,-15.3481 -28.2648,-15.3488 -28.2648,-15.3488 -26.9848,-15.3481 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -44.9848,-15.359 -44.9848,-15.359 -43.8248,-15.3583 -43.8248,-15.3583 -36.0548,-15.3536 -36.0548,-15.3536 -43.8248,-15.3583 -43.8248,-15.3583 -36.0548,-15.3536 -36.0548,-15.3536 -28.2648,-15.3488 -28.2648,-15.3488 -36.0548,-15.3536 -36.0548,-15.3536 -28.2648,-15.3488 -28.2648,-15.3488 -26.9848,-15.3481 -26.9848,-15.3481 -28.2648,-15.3488 -28.2648,-15.3488 -26.9848,-15.3481 -44.9848,-15.359 -43.8248,-15.3583 -43.8224,-19.3583 -44.9848,-15.359 -43.8224,-19.3583 -44.9824,-19.359 -43.8248,-15.3583 -36.0548,-15.3536 -36.0524,-19.3536 -43.8248,-15.3583 -36.0524,-19.3536 -43.8224,-19.3583 -36.0548,-15.3536 -28.2648,-15.3488 -28.2624,-19.3488 -36.0548,-15.3536 -28.2624,-19.3488 -36.0524,-19.3536 -28.2648,-15.3488 -26.9848,-15.3481 -26.9824,-19.3481 -28.2648,-15.3488 -26.9824,-19.3481 -28.2624,-19.3488 -44.9824,-19.359 -43.8224,-19.3583 -43.8222,-19.6583 -44.9824,-19.359 -43.8222,-19.6583 -44.9822,-19.659 -43.8224,-19.3583 -36.0524,-19.3536 -36.0522,-19.6536 -43.8224,-19.3583 -36.0522,-19.6536 -43.8222,-19.6583 -36.0524,-19.3536 -28.2624,-19.3488 -28.2622,-19.6488 -36.0524,-19.3536 -28.2622,-19.6488 -36.0522,-19.6536 -28.2624,-19.3488 -26.9824,-19.3481 -26.9822,-19.6481 -28.2624,-19.3488 -26.9822,-19.6481 -28.2622,-19.6488 -44.9822,-19.659 -43.8222,-19.6583 -43.8198,-23.6583 -44.9822,-19.659 -43.8198,-23.6583 -44.9798,-23.659 -43.8222,-19.6583 -36.0522,-19.6536 -36.0498,-23.6536 -43.8222,-19.6583 -36.0498,-23.6536 -43.8198,-23.6583 -36.0522,-19.6536 -28.2622,-19.6488 -28.2598,-23.6488 -36.0522,-19.6536 -28.2598,-23.6488 -36.0498,-23.6536 -28.2622,-19.6488 -26.9822,-19.6481 -26.9798,-23.6481 -28.2622,-19.6488 -26.9798,-23.6481 -28.2598,-23.6488 --93.3723,-85.2886 --63.3296,-89.2681 --63.3323,-85.2681 --93.3723,-85.2886 --93.3696,-89.2886 --63.3296,-89.2681 --93.3725,-84.9886 --63.3323,-85.2681 --63.3325,-84.9681 --93.3725,-84.9886 --93.3723,-85.2886 --63.3323,-85.2681 --93.3752,-80.9886 --63.3325,-84.9681 --63.3352,-80.9681 --93.3752,-80.9886 --93.3725,-84.9886 --63.3325,-84.9681 --93.3752,-80.9886 --63.3352,-80.9681 --63.3352,-80.9681 --93.3752,-80.9886 --93.3752,-80.9886 --63.3352,-80.9681 --93.3752,-80.9886 --63.3352,-80.9681 --63.3379,-76.9681 --93.3752,-80.9886 --63.3379,-76.9681 --93.3779,-76.9886 --93.3779,-76.9886 --63.3379,-76.9681 --63.3382,-76.6681 --93.3779,-76.9886 --63.3382,-76.6681 --93.3781,-76.6886 --93.3781,-76.6886 --63.3382,-76.6681 --63.3409,-72.6681 --93.3781,-76.6886 --63.3409,-72.6681 --93.3809,-72.6886 --45.3367,-85.26 --19.8306,-89.2686 --19.8293,-85.2686 --45.3367,-85.26 --45.338,-89.26 --19.8306,-89.2686 --19.8293,-85.2686 -9.68453,-89.2786 -9.68589,-85.2786 --19.8293,-85.2686 --19.8306,-89.2686 -9.68453,-89.2786 -9.68589,-85.2786 -38.7238,-89.2885 -38.7251,-85.2885 -9.68589,-85.2786 -9.68453,-89.2786 -38.7238,-89.2885 -38.7251,-85.2885 -82.8362,-89.2286 -82.8307,-85.2286 -38.7251,-85.2885 -38.7238,-89.2885 -82.8362,-89.2286 --45.3366,-84.96 --19.8293,-85.2686 --19.8292,-84.9686 --45.3366,-84.96 --45.3367,-85.26 --19.8293,-85.2686 --19.8292,-84.9686 -9.68589,-85.2786 -9.68599,-84.9786 --19.8292,-84.9686 --19.8293,-85.2686 -9.68589,-85.2786 -9.68599,-84.9786 -38.7251,-85.2885 -38.7252,-84.9885 -9.68599,-84.9786 -9.68589,-85.2786 -38.7251,-85.2885 -38.7252,-84.9885 -82.8307,-85.2286 -82.8303,-84.9286 -38.7252,-84.9885 -38.7251,-85.2885 -82.8307,-85.2286 --45.3352,-80.96 --19.8292,-84.9686 --19.8278,-80.9686 --45.3352,-80.96 --45.3366,-84.96 --19.8292,-84.9686 --19.8278,-80.9686 -9.68599,-84.9786 -9.68735,-80.9786 --19.8278,-80.9686 --19.8292,-84.9686 -9.68599,-84.9786 -9.68735,-80.9786 -38.7252,-84.9885 -38.7266,-80.9885 -9.68735,-80.9786 -9.68599,-84.9786 -38.7252,-84.9885 -38.7266,-80.9885 -82.8303,-84.9286 -82.8248,-80.9286 -38.7266,-80.9885 -38.7252,-84.9885 -82.8303,-84.9286 --45.3352,-80.96 --19.8278,-80.9686 --19.8278,-80.9686 --45.3352,-80.96 --45.3352,-80.96 --19.8278,-80.9686 --19.8278,-80.9686 -9.68735,-80.9786 -9.68735,-80.9786 --19.8278,-80.9686 --19.8278,-80.9686 -9.68735,-80.9786 -9.68735,-80.9786 -38.7266,-80.9885 -38.7266,-80.9885 -9.68735,-80.9786 -9.68735,-80.9786 -38.7266,-80.9885 -38.7266,-80.9885 -82.8248,-80.9286 -82.8248,-80.9286 -38.7266,-80.9885 -38.7266,-80.9885 -82.8248,-80.9286 --45.3352,-80.96 --19.8278,-80.9686 --19.8264,-76.9686 --45.3352,-80.96 --19.8264,-76.9686 --45.3339,-76.96 --19.8278,-80.9686 -9.68735,-80.9786 -9.6887,-76.9786 --19.8278,-80.9686 -9.6887,-76.9786 --19.8264,-76.9686 -9.68735,-80.9786 -38.7266,-80.9885 -38.7279,-76.9885 -9.68735,-80.9786 -38.7279,-76.9885 -9.6887,-76.9786 -38.7266,-80.9885 -82.8248,-80.9286 -82.8193,-76.9286 -38.7266,-80.9885 -82.8193,-76.9286 -38.7279,-76.9885 --45.3339,-76.96 --19.8264,-76.9686 --19.8263,-76.6686 --45.3339,-76.96 --19.8263,-76.6686 --45.3338,-76.66 --19.8264,-76.9686 -9.6887,-76.9786 -9.6888,-76.6786 --19.8264,-76.9686 -9.6888,-76.6786 --19.8263,-76.6686 -9.6887,-76.9786 -38.7279,-76.9885 -38.728,-76.6885 -9.6887,-76.9786 -38.728,-76.6885 -9.6888,-76.6786 -38.7279,-76.9885 -82.8193,-76.9286 -82.8189,-76.6286 -38.7279,-76.9885 -82.8189,-76.6286 -38.728,-76.6885 --45.3338,-76.66 --19.8263,-76.6686 --19.825,-72.6686 --45.3338,-76.66 --19.825,-72.6686 --45.3324,-72.66 --19.8263,-76.6686 -9.6888,-76.6786 -9.69016,-72.6786 --19.8263,-76.6686 -9.69016,-72.6786 --19.825,-72.6686 -9.6888,-76.6786 -38.728,-76.6885 -38.7294,-72.6885 -9.6888,-76.6786 -38.7294,-72.6885 -9.69016,-72.6786 -38.728,-76.6885 -82.8189,-76.6286 -82.8134,-72.6286 -38.728,-76.6885 -82.8134,-72.6286 -38.7294,-72.6885 --63.2952,34.0032 --61.6871,30.0025 --61.6852,34.0025 --63.2952,34.0032 --63.2971,30.0032 --61.6871,30.0025 --61.6852,34.0025 --53.8671,29.9989 --53.8652,33.9989 --61.6852,34.0025 --61.6871,30.0025 --53.8671,29.9989 --53.8652,33.9989 --47.4371,29.996 --47.4352,33.996 --53.8652,33.9989 --53.8671,29.9989 --47.4371,29.996 --47.4352,33.996 --45.2971,29.995 --45.2952,33.995 --47.4352,33.996 --47.4371,29.996 --45.2971,29.995 --63.2952,34.0032 --61.6852,34.0025 --61.6852,34.0025 --63.2952,34.0032 --63.2952,34.0032 --61.6852,34.0025 --61.6852,34.0025 --53.8652,33.9989 --53.8652,33.9989 --61.6852,34.0025 --61.6852,34.0025 --53.8652,33.9989 --53.8652,33.9989 --47.4352,33.996 --47.4352,33.996 --53.8652,33.9989 --53.8652,33.9989 --47.4352,33.996 --47.4352,33.996 --45.2952,33.995 --45.2952,33.995 --47.4352,33.996 --47.4352,33.996 --45.2952,33.995 --93.3781,-76.6886 --94.4243,-72.6909 --94.4216,-76.6893 --93.3781,-76.6886 --93.3809,-72.6886 --94.4243,-72.6909 --94.4216,-76.6893 --94.5836,-72.6866 --95.0194,-76.6568 --94.4216,-76.6893 --94.4243,-72.6909 --94.5836,-72.6866 --95.0194,-76.6568 --94.7425,-72.6668 --95.61,-76.5589 --95.0194,-76.6568 --94.5836,-72.6866 --94.7425,-72.6668 --95.61,-76.5589 --94.8993,-72.6308 --96.1863,-76.3967 --95.61,-76.5589 --94.7425,-72.6668 --94.8993,-72.6308 --96.1863,-76.3967 --95.0524,-72.5782 --96.7414,-76.1722 --96.1863,-76.3967 --94.8993,-72.6308 --95.0524,-72.5782 --96.7414,-76.1722 --95.1996,-72.5087 --97.2684,-75.8882 --96.7414,-76.1722 --95.0524,-72.5782 --95.1996,-72.5087 --97.2684,-75.8882 --95.3387,-72.4224 --97.7611,-75.548 --97.2684,-75.8882 --95.1996,-72.5087 --95.3387,-72.4224 --97.7611,-75.548 --95.3273,-72.4466 --98.1385,-75.218 --97.7611,-75.548 --95.3387,-72.4224 --95.3273,-72.4466 --98.1385,-75.218 --95.2638,-72.5278 --98.4305,-74.877 --98.1385,-75.218 --95.3273,-72.4466 --95.2638,-72.5278 --98.4305,-74.877 --95.2103,-72.6153 --98.6721,-74.4987 --98.4305,-74.877 --95.2638,-72.5278 --95.2103,-72.6153 --98.6721,-74.4987 --95.1667,-72.708 --98.8585,-74.0903 --98.6721,-74.4987 --95.2103,-72.6153 --95.1667,-72.708 --98.8585,-74.0903 --95.1325,-72.8052 --98.9861,-73.6599 --98.8585,-74.0903 --95.1667,-72.708 --95.1325,-72.8052 --98.9861,-73.6599 --95.1077,-72.9066 --99.0525,-73.2159 --98.9861,-73.6599 --95.1325,-72.8052 --95.1077,-72.9066 --99.0525,-73.2159 --95.0652,-71.1158 --99.0652,-71.1221 --99.0525,-73.2159 --95.1077,-72.9066 --95.0652,-71.1158 --93.3779,-76.9886 --94.4216,-76.6893 --94.4214,-76.9893 --93.3779,-76.9886 --93.3781,-76.6886 --94.4216,-76.6893 --94.4214,-76.9893 --95.0194,-76.6568 --95.0521,-76.955 --94.4214,-76.9893 --94.4216,-76.6893 --95.0194,-76.6568 --95.0521,-76.955 --95.61,-76.5589 --95.6753,-76.8517 --95.0521,-76.955 --95.0194,-76.6568 --95.61,-76.5589 --95.6753,-76.8517 --96.1863,-76.3967 --96.2834,-76.6806 --95.6753,-76.8517 --95.61,-76.5589 --96.1863,-76.3967 --96.2834,-76.6806 --96.7414,-76.1722 --96.869,-76.4437 --96.2834,-76.6806 --96.1863,-76.3967 --96.7414,-76.1722 --96.869,-76.4437 --97.2684,-75.8882 --97.425,-76.1441 --96.869,-76.4437 --96.7414,-76.1722 --97.2684,-75.8882 --97.425,-76.1441 --97.7611,-75.548 --97.9448,-75.7851 --97.425,-76.1441 --97.2684,-75.8882 --97.7611,-75.548 --97.9448,-75.7851 --98.1385,-75.218 --98.3521,-75.4286 --97.9448,-75.7851 --97.7611,-75.548 --98.1385,-75.218 --98.3521,-75.4286 --98.4305,-74.877 --98.6714,-75.0558 --98.3521,-75.4286 --98.1385,-75.218 --98.4305,-74.877 --98.6714,-75.0558 --98.6721,-74.4987 --98.9356,-74.6421 --98.6714,-75.0558 --98.4305,-74.877 --98.6721,-74.4987 --98.9356,-74.6421 --98.8585,-74.0903 --99.1395,-74.1955 --98.9356,-74.6421 --98.6721,-74.4987 --98.8585,-74.0903 --99.1395,-74.1955 --98.9861,-73.6599 --99.279,-73.7249 --99.1395,-74.1955 --98.8585,-74.0903 --98.9861,-73.6599 --99.279,-73.7249 --99.0525,-73.2159 --99.3515,-73.2394 --99.279,-73.7249 --98.9861,-73.6599 --99.0525,-73.2159 --99.3515,-73.2394 --99.0652,-71.1221 --99.3652,-71.1226 --99.3515,-73.2394 --99.0525,-73.2159 --99.0652,-71.1221 --93.3752,-80.9886 --94.4214,-76.9893 --94.4186,-80.9893 --93.3752,-80.9886 --93.3779,-76.9886 --94.4214,-76.9893 --94.4186,-80.9893 --95.0521,-76.955 --95.4885,-80.9312 --94.4186,-80.9893 --94.4214,-76.9893 --95.0521,-76.955 --95.4885,-80.9312 --95.6753,-76.8517 --96.5456,-80.7559 --95.4885,-80.9312 --95.0521,-76.955 --95.6753,-76.8517 --96.5456,-80.7559 --96.2834,-76.6806 --97.577,-80.4656 --96.5456,-80.7559 --95.6753,-76.8517 --96.2834,-76.6806 --97.577,-80.4656 --96.869,-76.4437 --98.5703,-80.0639 --97.577,-80.4656 --96.2834,-76.6806 --96.869,-76.4437 --98.5703,-80.0639 --97.425,-76.1441 --99.5135,-79.5556 --98.5703,-80.0639 --96.869,-76.4437 --97.425,-76.1441 --99.5135,-79.5556 --97.9448,-75.7851 --100.395,-78.9468 --99.5135,-79.5556 --97.425,-76.1441 --97.9448,-75.7851 --100.395,-78.9468 --98.3521,-75.4286 --101.201,-78.2368 --100.395,-78.9468 --97.9448,-75.7851 --98.3521,-75.4286 --101.201,-78.2368 --98.6714,-75.0558 --101.884,-77.439 --101.201,-78.2368 --98.3521,-75.4286 --98.6714,-75.0558 --101.884,-77.439 --98.9356,-74.6421 --102.449,-76.5537 --101.884,-77.439 --98.6714,-75.0558 --98.9356,-74.6421 --102.449,-76.5537 --99.1395,-74.1955 --102.885,-75.5981 --102.449,-76.5537 --98.9356,-74.6421 --99.1395,-74.1955 --102.885,-75.5981 --99.279,-73.7249 --103.184,-74.591 --102.885,-75.5981 --99.1395,-74.1955 --99.279,-73.7249 --103.184,-74.591 --99.3515,-73.2394 --103.339,-73.5522 --103.184,-74.591 --99.279,-73.7249 --99.3515,-73.2394 --103.339,-73.5522 --99.3652,-71.1226 --103.365,-71.1289 --103.339,-73.5522 --99.3515,-73.2394 --99.3652,-71.1226 --93.3752,-80.9886 --94.4186,-80.9893 --94.4186,-80.9893 --93.3752,-80.9886 --93.3752,-80.9886 --94.4186,-80.9893 --94.4186,-80.9893 --95.4885,-80.9312 --95.4885,-80.9312 --94.4186,-80.9893 --94.4186,-80.9893 --95.4885,-80.9312 --95.4885,-80.9312 --96.5456,-80.7559 --96.5456,-80.7559 --95.4885,-80.9312 --95.4885,-80.9312 --96.5456,-80.7559 --96.5456,-80.7559 --97.577,-80.4656 --97.577,-80.4656 --96.5456,-80.7559 --96.5456,-80.7559 --97.577,-80.4656 --97.577,-80.4656 --98.5703,-80.0639 --98.5703,-80.0639 --97.577,-80.4656 --97.577,-80.4656 --98.5703,-80.0639 --98.5703,-80.0639 --99.5135,-79.5556 --99.5135,-79.5556 --98.5703,-80.0639 --98.5703,-80.0639 --99.5135,-79.5556 --99.5135,-79.5556 --100.395,-78.9468 --100.395,-78.9468 --99.5135,-79.5556 --99.5135,-79.5556 --100.395,-78.9468 --100.395,-78.9468 --101.201,-78.2368 --101.201,-78.2368 --100.395,-78.9468 --100.395,-78.9468 --101.201,-78.2368 --101.201,-78.2368 --101.884,-77.439 --101.884,-77.439 --101.201,-78.2368 --101.201,-78.2368 --101.884,-77.439 --101.884,-77.439 --102.449,-76.5537 --102.449,-76.5537 --101.884,-77.439 --101.884,-77.439 --102.449,-76.5537 --102.449,-76.5537 --102.885,-75.5981 --102.885,-75.5981 --102.449,-76.5537 --102.449,-76.5537 --102.885,-75.5981 --102.885,-75.5981 --103.184,-74.591 --103.184,-74.591 --102.885,-75.5981 --102.885,-75.5981 --103.184,-74.591 --103.184,-74.591 --103.339,-73.5522 --103.339,-73.5522 --103.184,-74.591 --103.184,-74.591 --103.339,-73.5522 --103.339,-73.5522 --103.365,-71.1289 --103.365,-71.1289 --103.339,-73.5522 --103.339,-73.5522 --103.365,-71.1289 --93.3752,-80.9886 --94.4186,-80.9893 --94.4159,-84.9893 --93.3752,-80.9886 --94.4159,-84.9893 --93.3725,-84.9886 --94.4186,-80.9893 --95.4885,-80.9312 --95.9249,-84.9073 --94.4186,-80.9893 --95.9249,-84.9073 --94.4159,-84.9893 --95.4885,-80.9312 --96.5456,-80.7559 --97.4158,-84.6601 --95.4885,-80.9312 --97.4158,-84.6601 --95.9249,-84.9073 --96.5456,-80.7559 --97.577,-80.4656 --98.8705,-84.2507 --96.5456,-80.7559 --98.8705,-84.2507 --97.4158,-84.6601 --97.577,-80.4656 --98.5703,-80.0639 --100.272,-83.6841 --97.577,-80.4656 --100.272,-83.6841 --98.8705,-84.2507 --98.5703,-80.0639 --99.5135,-79.5556 --101.602,-82.9671 --98.5703,-80.0639 --101.602,-82.9671 --100.272,-83.6841 --99.5135,-79.5556 --100.395,-78.9468 --102.845,-82.1084 --99.5135,-79.5556 --102.845,-82.1084 --101.602,-82.9671 --100.395,-78.9468 --101.201,-78.2368 --104.049,-81.045 --100.395,-78.9468 --104.049,-81.045 --102.845,-82.1084 --101.201,-78.2368 --101.884,-77.439 --105.096,-79.8222 --101.201,-78.2368 --105.096,-79.8222 --104.049,-81.045 --101.884,-77.439 --102.449,-76.5537 --105.963,-78.4653 --101.884,-77.439 --105.963,-78.4653 --105.096,-79.8222 --102.449,-76.5537 --102.885,-75.5981 --106.632,-77.0007 --102.449,-76.5537 --106.632,-77.0007 --105.963,-78.4653 --102.885,-75.5981 --103.184,-74.591 --107.089,-75.4572 --102.885,-75.5981 --107.089,-75.4572 --106.632,-77.0007 --103.184,-74.591 --103.339,-73.5522 --107.327,-73.8649 --103.184,-74.591 --107.327,-73.8649 --107.089,-75.4572 --103.339,-73.5522 --103.365,-71.1289 --107.365,-71.1353 --103.339,-73.5522 --107.365,-71.1353 --107.327,-73.8649 --93.3725,-84.9886 --94.4159,-84.9893 --94.4157,-85.2893 --93.3725,-84.9886 --94.4157,-85.2893 --93.3723,-85.2886 --94.4159,-84.9893 --95.9249,-84.9073 --95.9577,-85.2055 --94.4159,-84.9893 --95.9577,-85.2055 --94.4157,-85.2893 --95.9249,-84.9073 --97.4158,-84.6601 --97.4811,-84.9529 --95.9249,-84.9073 --97.4811,-84.9529 --95.9577,-85.2055 --97.4158,-84.6601 --98.8705,-84.2507 --98.9676,-84.5346 --97.4158,-84.6601 --98.9676,-84.5346 --97.4811,-84.9529 --98.8705,-84.2507 --100.272,-83.6841 --100.399,-83.9556 --98.8705,-84.2507 --100.399,-83.9556 --98.9676,-84.5346 --100.272,-83.6841 --101.602,-82.9671 --101.759,-83.223 --100.272,-83.6841 --101.759,-83.223 --100.399,-83.9556 --101.602,-82.9671 --102.845,-82.1084 --103.029,-82.3455 --101.602,-82.9671 --103.029,-82.3455 --101.759,-83.223 --102.845,-82.1084 --104.049,-81.045 --104.263,-81.2556 --102.845,-82.1084 --104.263,-81.2556 --103.029,-82.3455 --104.049,-81.045 --105.096,-79.8222 --105.337,-80.001 --104.049,-81.045 --105.337,-80.001 --104.263,-81.2556 --105.096,-79.8222 --105.963,-78.4653 --106.226,-78.6087 --105.096,-79.8222 --106.226,-78.6087 --105.337,-80.001 --105.963,-78.4653 --106.632,-77.0007 --106.912,-77.1059 --105.963,-78.4653 --106.912,-77.1059 --106.226,-78.6087 --106.632,-77.0007 --107.089,-75.4572 --107.382,-75.5222 --106.632,-77.0007 --107.382,-75.5222 --106.912,-77.1059 --107.089,-75.4572 --107.327,-73.8649 --107.626,-73.8884 --107.089,-75.4572 --107.626,-73.8884 --107.382,-75.5222 --107.327,-73.8649 --107.365,-71.1353 --107.665,-71.1358 --107.327,-73.8649 --107.665,-71.1358 --107.626,-73.8884 --93.3723,-85.2886 --94.4157,-85.2893 --94.413,-89.2893 --93.3723,-85.2886 --94.413,-89.2893 --93.3696,-89.2886 --94.4157,-85.2893 --95.9577,-85.2055 --96.3941,-89.1816 --94.4157,-85.2893 --96.3941,-89.1816 --94.413,-89.2893 --95.9577,-85.2055 --97.4811,-84.9529 --98.3513,-88.8571 --95.9577,-85.2055 --98.3513,-88.8571 --96.3941,-89.1816 --97.4811,-84.9529 --98.9676,-84.5346 --100.261,-88.3196 --97.4811,-84.9529 --100.261,-88.3196 --98.3513,-88.8571 --98.9676,-84.5346 --100.399,-83.9556 --102.1,-87.5758 --98.9676,-84.5346 --102.1,-87.5758 --100.261,-88.3196 --100.399,-83.9556 --101.759,-83.223 --103.847,-86.6345 --100.399,-83.9556 --103.847,-86.6345 --102.1,-87.5758 --101.759,-83.223 --103.029,-82.3455 --105.48,-85.5072 --101.759,-83.223 --105.48,-85.5072 --103.847,-86.6345 --103.029,-82.3455 --104.263,-81.2556 --107.111,-84.0638 --103.029,-82.3455 --107.111,-84.0638 --105.48,-85.5072 --104.263,-81.2556 --105.337,-80.001 --108.55,-82.3842 --104.263,-81.2556 --108.55,-82.3842 --107.111,-84.0638 --105.337,-80.001 --106.226,-78.6087 --109.74,-80.5203 --105.337,-80.001 --109.74,-80.5203 --108.55,-82.3842 --106.226,-78.6087 --106.912,-77.1059 --110.658,-78.5085 --106.226,-78.6087 --110.658,-78.5085 --109.74,-80.5203 --106.912,-77.1059 --107.382,-75.5222 --111.287,-76.3883 --106.912,-77.1059 --111.287,-76.3883 --110.658,-78.5085 --107.382,-75.5222 --107.626,-73.8884 --111.614,-74.2011 --107.382,-75.5222 --111.614,-74.2011 --111.287,-76.3883 --107.626,-73.8884 --107.665,-71.1358 --111.665,-71.1421 --107.626,-73.8884 --111.665,-71.1421 --111.614,-74.2011 --63.2952,34.0032 --61.6852,34.0025 --61.6852,34.0025 --63.2952,34.0032 --63.2952,34.0032 --61.6852,34.0025 --61.6852,34.0025 --53.8652,33.9989 --53.8652,33.9989 --61.6852,34.0025 --61.6852,34.0025 --53.8652,33.9989 --53.8652,33.9989 --47.4352,33.996 --47.4352,33.996 --53.8652,33.9989 --53.8652,33.9989 --47.4352,33.996 --47.4352,33.996 --45.2952,33.995 --45.2952,33.995 --47.4352,33.996 --47.4352,33.996 --45.2952,33.995 --63.2952,34.0032 --61.6852,34.0025 --61.6834,38.0025 --63.2952,34.0032 --61.6834,38.0025 --63.2934,38.0032 --61.6852,34.0025 --53.8652,33.9989 --53.8634,37.9989 --61.6852,34.0025 --53.8634,37.9989 --61.6834,38.0025 --53.8652,33.9989 --47.4352,33.996 --47.4334,37.996 --53.8652,33.9989 --47.4334,37.996 --53.8634,37.9989 --47.4352,33.996 --45.2952,33.995 --45.2934,37.995 --47.4352,33.996 --45.2934,37.995 --47.4334,37.996 --63.2934,38.0032 --61.6834,38.0025 --61.6832,38.3025 --63.2934,38.0032 --61.6832,38.3025 --63.2932,38.3032 --61.6834,38.0025 --53.8634,37.9989 --53.8632,38.2989 --61.6834,38.0025 --53.8632,38.2989 --61.6832,38.3025 --53.8634,37.9989 --47.4334,37.996 --47.4332,38.296 --53.8634,37.9989 --47.4332,38.296 --53.8632,38.2989 --47.4334,37.996 --45.2934,37.995 --45.2932,38.295 --47.4334,37.996 --45.2932,38.295 --47.4332,38.296 --63.2932,38.3032 --61.6832,38.3025 --61.6814,42.3025 --63.2932,38.3032 --61.6814,42.3025 --63.2914,42.3032 --61.6832,38.3025 --53.8632,38.2989 --53.8614,42.2989 --61.6832,38.3025 --53.8614,42.2989 --61.6814,42.3025 --53.8632,38.2989 --47.4332,38.296 --47.4314,42.296 --53.8632,38.2989 --47.4314,42.296 --53.8614,42.2989 --47.4332,38.296 --45.2932,38.295 --45.2914,42.295 --47.4332,38.296 --45.2914,42.295 --47.4314,42.296 --45.2974,29.695 --46.3006,29.8693 --46.2265,29.5786 --45.2974,29.695 --45.2972,29.995 --46.3006,29.8693 --46.2265,29.5786 --47.2417,29.4993 --47.098,29.236 --46.2265,29.5786 --46.3006,29.8693 --47.2417,29.4993 --47.098,29.236 --48.062,28.908 --47.8576,28.6884 --47.098,29.236 --47.2417,29.4993 --48.062,28.908 --47.8576,28.6884 --48.7544,28.1075 --48.519,27.9215 --47.8576,28.6884 --48.062,28.908 --48.7544,28.1075 --48.519,27.9215 --49.3434,27.2848 --49.0858,27.1309 --48.519,27.9215 --48.7544,28.1075 --49.3434,27.2848 --49.0858,27.1309 --49.7845,26.3681 --49.5036,26.2628 --49.0858,27.1309 --49.3434,27.2848 --49.7845,26.3681 --49.5036,26.2628 --50.0544,25.3872 --49.7592,25.3339 --49.5036,26.2628 --49.7845,26.3681 --50.0544,25.3872 --49.7592,25.3339 --50.1444,24.3817 --49.8444,24.3818 --49.7592,25.3339 --50.0544,25.3872 --50.1444,24.3817 --49.8444,24.3818 --50.1444,24.3617 --49.8444,24.3618 --49.8444,24.3818 --50.1444,24.3817 --50.1444,24.3617 --45.299,25.695 --46.2265,29.5786 --45.2385,25.7026 --45.299,25.695 --45.2974,29.695 --46.2265,29.5786 --45.2385,25.7026 --47.098,29.236 --45.1817,25.7249 --45.2385,25.7026 --46.2265,29.5786 --47.098,29.236 --45.1817,25.7249 --47.8576,28.6884 --45.1322,25.7606 --45.1817,25.7249 --47.098,29.236 --47.8576,28.6884 --45.1322,25.7606 --48.519,27.9215 --45.38,25.4422 --45.1322,25.7606 --47.8576,28.6884 --48.519,27.9215 --45.38,25.4422 --49.0858,27.1309 --45.652,25.0794 --45.38,25.4422 --48.519,27.9215 --49.0858,27.1309 --45.652,25.0794 --49.5036,26.2628 --45.7579,24.8592 --45.652,25.0794 --49.0858,27.1309 --49.5036,26.2628 --45.7579,24.8592 --49.7592,25.3339 --45.8228,24.6236 --45.7579,24.8592 --49.5036,26.2628 --49.7592,25.3339 --45.8228,24.6236 --49.8444,24.3818 --45.8444,24.3821 --45.8228,24.6236 --49.7592,25.3339 --49.8444,24.3818 --45.8444,24.3821 --49.8444,24.3618 --45.8444,24.3621 --45.8444,24.3821 --49.8444,24.3818 --49.8444,24.3618 --45.299,25.695 --45.2385,25.7026 --45.2385,25.7026 --45.299,25.695 --45.299,25.695 --45.2385,25.7026 --45.2385,25.7026 --45.1817,25.7249 --45.1817,25.7249 --45.2385,25.7026 --45.2385,25.7026 --45.1817,25.7249 --45.1817,25.7249 --45.1322,25.7606 --45.1322,25.7606 --45.1817,25.7249 --45.1817,25.7249 --45.1322,25.7606 --45.1322,25.7606 --45.38,25.4422 --45.38,25.4422 --45.1322,25.7606 --45.1322,25.7606 --45.38,25.4422 --45.38,25.4422 --45.652,25.0794 --45.652,25.0794 --45.38,25.4422 --45.38,25.4422 --45.652,25.0794 --45.652,25.0794 --45.7579,24.8592 --45.7579,24.8592 --45.652,25.0794 --45.652,25.0794 --45.7579,24.8592 --45.7579,24.8592 --45.8228,24.6236 --45.8228,24.6236 --45.7579,24.8592 --45.7579,24.8592 --45.8228,24.6236 --45.8228,24.6236 --45.8444,24.3821 --45.8444,24.3821 --45.8228,24.6236 --45.8228,24.6236 --45.8444,24.3821 --45.8444,24.3821 --45.8444,24.3621 --45.8444,24.3621 --45.8444,24.3821 --45.8444,24.3821 --45.8444,24.3621 --54.1444,24.3614 --50.1445,25.5017 --54.1445,25.5014 --54.1444,24.3614 --50.1444,24.3617 --50.1445,25.5017 --54.1445,25.5014 --50.1446,26.5808 --54.1446,26.5805 --54.1445,25.5014 --50.1445,25.5017 --50.1446,26.5808 --54.1446,26.5805 --50.1081,27.1414 --54.0744,27.6596 --54.1446,26.5805 --50.1446,26.5808 --50.1081,27.1414 --54.0744,27.6596 --49.9993,27.6926 --53.865,28.7206 --54.0744,27.6596 --50.1081,27.1414 --49.9993,27.6926 --53.865,28.7206 --49.82,28.225 --53.5197,29.7454 --53.865,28.7206 --49.9993,27.6926 --49.82,28.225 --53.5197,29.7454 --49.5731,28.7296 --53.0446,30.7169 --53.5197,29.7454 --49.82,28.225 --49.5731,28.7296 --53.0446,30.7169 --49.2629,29.198 --52.4475,31.6185 --53.0446,30.7169 --49.5731,28.7296 --49.2629,29.198 --52.4475,31.6185 --49.0213,29.4708 --51.7588,32.3872 --52.4475,31.6185 --49.2629,29.198 --49.0213,29.4708 --51.7588,32.3872 --48.7629,29.6749 --50.9676,33.0125 --51.7588,32.3872 --49.0213,29.4708 --48.7629,29.6749 --50.9676,33.0125 --48.4738,29.8324 --50.082,33.4949 --50.9676,33.0125 --48.7629,29.6749 --48.4738,29.8324 --50.082,33.4949 --48.1621,29.9388 --49.1276,33.8205 --50.082,33.4949 --48.4738,29.8324 --48.1621,29.9388 --49.1276,33.8205 --47.837,29.9908 --48.1318,33.9799 --49.1276,33.8205 --48.1621,29.9388 --47.837,29.9908 --48.1318,33.9799 --47.1271,29.9958 --47.1252,33.9958 --48.1318,33.9799 --47.837,29.9908 --47.1271,29.9958 --47.1252,33.9958 --45.2971,29.995 --45.2952,33.995 --47.1252,33.9958 --47.1271,29.9958 --45.2971,29.995 --54.1444,24.3614 --54.1445,25.5014 --54.1445,25.5014 --54.1444,24.3614 --54.1444,24.3614 --54.1445,25.5014 --54.1445,25.5014 --54.1446,26.5805 --54.1446,26.5805 --54.1445,25.5014 --54.1445,25.5014 --54.1446,26.5805 --54.1446,26.5805 --54.0744,27.6596 --54.0744,27.6596 --54.1446,26.5805 --54.1446,26.5805 --54.0744,27.6596 --54.0744,27.6596 --53.865,28.7206 --53.865,28.7206 --54.0744,27.6596 --54.0744,27.6596 --53.865,28.7206 --53.865,28.7206 --53.5197,29.7454 --53.5197,29.7454 --53.865,28.7206 --53.865,28.7206 --53.5197,29.7454 --53.5197,29.7454 --53.0446,30.7169 --53.0446,30.7169 --53.5197,29.7454 --53.5197,29.7454 --53.0446,30.7169 --53.0446,30.7169 --52.4475,31.6185 --52.4475,31.6185 --53.0446,30.7169 --53.0446,30.7169 --52.4475,31.6185 --52.4475,31.6185 --51.7588,32.3872 --51.7588,32.3872 --52.4475,31.6185 --52.4475,31.6185 --51.7588,32.3872 --51.7588,32.3872 --50.9676,33.0125 --50.9676,33.0125 --51.7588,32.3872 --51.7588,32.3872 --50.9676,33.0125 --50.9676,33.0125 --50.082,33.4949 --50.082,33.4949 --50.9676,33.0125 --50.9676,33.0125 --50.082,33.4949 --50.082,33.4949 --49.1276,33.8205 --49.1276,33.8205 --50.082,33.4949 --50.082,33.4949 --49.1276,33.8205 --49.1276,33.8205 --48.1318,33.9799 --48.1318,33.9799 --49.1276,33.8205 --49.1276,33.8205 --48.1318,33.9799 --48.1318,33.9799 --47.1252,33.9958 --47.1252,33.9958 --48.1318,33.9799 --48.1318,33.9799 --47.1252,33.9958 --47.1252,33.9958 --45.2952,33.995 --45.2952,33.995 --47.1252,33.9958 --47.1252,33.9958 --45.2952,33.995 --54.1444,24.3614 --54.1445,25.5014 --54.1445,25.5014 --54.1444,24.3614 --54.1444,24.3614 --54.1445,25.5014 --54.1445,25.5014 --54.1374,26.5257 --54.1374,26.5257 --54.1445,25.5014 --54.1445,25.5014 --54.1374,26.5257 --54.1374,26.5257 --54.0305,27.5925 --54.0305,27.5925 --54.1374,26.5257 --54.1374,26.5257 --54.0305,27.5925 --54.0305,27.5925 --53.7966,28.6388 --53.7966,28.6388 --54.0305,27.5925 --54.0305,27.5925 --53.7966,28.6388 --53.7966,28.6388 --53.4391,29.6496 --53.4391,29.6496 --53.7966,28.6388 --53.7966,28.6388 --53.4391,29.6496 --53.4391,29.6496 --52.9632,30.6103 --52.9632,30.6103 --53.4391,29.6496 --53.4391,29.6496 --52.9632,30.6103 --52.9632,30.6103 --52.3758,31.5072 --52.3758,31.5072 --52.9632,30.6103 --52.9632,30.6103 --52.3758,31.5072 --52.3758,31.5072 --51.7014,32.2784 --51.7014,32.2784 --52.3758,31.5072 --52.3758,31.5072 --51.7014,32.2784 --51.7014,32.2784 --50.8972,32.9336 --50.8972,32.9336 --51.7014,32.2784 --51.7014,32.2784 --50.8972,32.9336 --50.8972,32.9336 --49.9938,33.4433 --49.9938,33.4433 --50.8972,32.9336 --50.8972,32.9336 --49.9938,33.4433 --49.9938,33.4433 --49.0172,33.7928 --49.0172,33.7928 --49.9938,33.4433 --49.9938,33.4433 --49.0172,33.7928 --49.0172,33.7928 --47.9955,33.972 --47.9955,33.972 --49.0172,33.7928 --49.0172,33.7928 --47.9955,33.972 --47.9955,33.972 --46.9652,33.9958 --46.9652,33.9958 --47.9955,33.972 --47.9955,33.972 --46.9652,33.9958 --46.9652,33.9958 --45.2952,33.995 --45.2952,33.995 --46.9652,33.9958 --46.9652,33.9958 --45.2952,33.995 --54.1444,24.3614 --54.1445,25.5014 --58.1445,25.501 --54.1444,24.3614 --58.1445,25.501 --58.1444,24.361 --54.1445,25.5014 --54.1374,26.5257 --58.1342,26.6853 --54.1445,25.5014 --58.1342,26.6853 --58.1445,25.501 --54.1374,26.5257 --54.0305,27.5925 --57.9794,28.2294 --54.1374,26.5257 --57.9794,28.2294 --58.1342,26.6853 --54.0305,27.5925 --53.7966,28.6388 --57.6409,29.7439 --54.0305,27.5925 --57.6409,29.7439 --57.9794,28.2294 --53.7966,28.6388 --53.4391,29.6496 --57.1235,31.207 --53.7966,28.6388 --57.1235,31.207 --57.6409,29.7439 --53.4391,29.6496 --52.9632,30.6103 --56.4347,32.5976 --53.4391,29.6496 --56.4347,32.5976 --57.1235,31.207 --52.9632,30.6103 --52.3758,31.5072 --55.5844,33.8957 --52.9632,30.6103 --55.5844,33.8957 --56.4347,32.5976 --52.3758,31.5072 --51.7014,32.2784 --54.4821,35.1538 --52.3758,31.5072 --54.4821,35.1538 --55.5844,33.8957 --51.7014,32.2784 --50.8972,32.9336 --53.1514,36.238 --51.7014,32.2784 --53.1514,36.238 --54.4821,35.1538 --50.8972,32.9336 --49.9938,33.4433 --51.6564,37.0814 --50.8972,32.9336 --51.6564,37.0814 --53.1514,36.238 --49.9938,33.4433 --49.0172,33.7928 --50.0403,37.6597 --49.9938,33.4433 --50.0403,37.6597 --51.6564,37.0814 --49.0172,33.7928 --47.9955,33.972 --48.3497,37.9563 --49.0172,33.7928 --48.3497,37.9563 --50.0403,37.6597 --47.9955,33.972 --46.9652,33.9958 --46.9634,37.9958 --47.9955,33.972 --46.9634,37.9958 --48.3497,37.9563 --46.9652,33.9958 --45.2952,33.995 --45.2934,37.995 --46.9652,33.9958 --45.2934,37.995 --46.9634,37.9958 --63.299,25.7032 --63.2952,25.7028 --63.2952,25.7028 --63.299,25.7032 --63.299,25.7032 --63.2952,25.7028 --63.2952,25.7028 --63.2917,25.7014 --63.2917,25.7014 --63.2952,25.7028 --63.2952,25.7028 --63.2917,25.7014 --63.2917,25.7014 --63.2885,25.6993 --63.2885,25.6993 --63.2917,25.7014 --63.2917,25.7014 --63.2885,25.6993 --63.2885,25.6993 --62.6836,25.0016 --62.6836,25.0016 --63.2885,25.6993 --63.2885,25.6993 --62.6836,25.0016 --62.6836,25.0016 --62.5758,24.8504 --62.5758,24.8504 --62.6836,25.0016 --62.6836,25.0016 --62.5758,24.8504 --62.5758,24.8504 --62.4985,24.6816 --62.4985,24.6816 --62.5758,24.8504 --62.5758,24.8504 --62.4985,24.6816 --62.4985,24.6816 --62.4545,24.5012 --62.4545,24.5012 --62.4985,24.6816 --62.4985,24.6816 --62.4545,24.5012 --62.4545,24.5012 --62.4444,24.3607 --62.4444,24.3607 --62.4545,24.5012 --62.4545,24.5012 --62.4444,24.3607 --63.299,25.7032 --63.2952,25.7028 --62.3426,29.5877 --63.299,25.7032 --62.3426,29.5877 --63.2972,29.7032 --63.2952,25.7028 --63.2917,25.7014 --61.4429,29.2486 --63.2952,25.7028 --61.4429,29.2486 --62.3426,29.5877 --63.2917,25.7014 --63.2885,25.6993 --60.6496,28.7053 --63.2917,25.7014 --60.6496,28.7053 --61.4429,29.2486 --63.2885,25.6993 --62.6836,25.0016 --59.6611,27.6218 --63.2885,25.6993 --59.6611,27.6218 --60.6496,28.7053 --62.6836,25.0016 --62.5758,24.8504 --59.1129,26.8526 --62.6836,25.0016 --59.1129,26.8526 --59.6611,27.6218 --62.5758,24.8504 --62.4985,24.6816 --58.7199,25.9937 --62.5758,24.8504 --58.7199,25.9937 --59.1129,26.8526 --62.4985,24.6816 --62.4545,24.5012 --58.4961,25.0761 --62.4985,24.6816 --58.4961,25.0761 --58.7199,25.9937 --62.4545,24.5012 --62.4444,24.3607 --58.4444,24.3612 --62.4545,24.5012 --58.4444,24.3612 --58.4961,25.0761 --63.2972,29.7032 --62.3426,29.5877 --62.2712,29.8791 --63.2972,29.7032 --62.2712,29.8791 --63.2971,30.0032 --62.3426,29.5877 --61.4429,29.2486 --61.3043,29.5146 --62.3426,29.5877 --61.3043,29.5146 --62.2712,29.8791 --61.4429,29.2486 --60.6496,28.7053 --60.4517,28.9308 --61.4429,29.2486 --60.4517,28.9308 --61.3043,29.5146 --60.6496,28.7053 --59.6611,27.6218 --59.4344,27.8183 --60.6496,28.7053 --59.4344,27.8183 --60.4517,28.9308 --59.6611,27.6218 --59.1129,26.8526 --58.8532,27.0027 --59.6611,27.6218 --58.8532,27.0027 --59.4344,27.8183 --59.1129,26.8526 --58.7199,25.9937 --58.4365,26.0921 --59.1129,26.8526 --58.4365,26.0921 --58.8532,27.0027 --58.7199,25.9937 --58.4961,25.0761 --58.1992,25.1192 --58.7199,25.9937 --58.1992,25.1192 --58.4365,26.0921 --58.4961,25.0761 --58.4444,24.3612 --58.1444,24.3612 --58.4961,25.0761 --58.1444,24.3612 --58.1992,25.1192 --63.2952,34.0032 --61.6871,30.0025 --61.6852,34.0025 --63.2952,34.0032 --63.2971,30.0032 --61.6871,30.0025 --61.6852,34.0025 --60.9778,29.9933 --60.6563,33.9803 --61.6852,34.0025 --61.6871,30.0025 --60.9778,29.9933 --60.6563,33.9803 --60.5645,29.9285 --59.6508,33.8227 --60.6563,33.9803 --60.9778,29.9933 --60.5645,29.9285 --59.6508,33.8227 --60.1655,29.8027 --58.6801,33.5166 --59.6508,33.8227 --60.5645,29.9285 --60.1655,29.8027 --58.6801,33.5166 --59.7898,29.6186 --57.766,33.0689 --58.6801,33.5166 --60.1655,29.8027 --59.7898,29.6186 --57.766,33.0689 --59.4458,29.3805 --56.9292,32.4896 --57.766,33.0689 --59.7898,29.6186 --59.4458,29.3805 --56.9292,32.4896 --59.1412,29.0937 --56.1882,31.7918 --56.9292,32.4896 --59.4458,29.3805 --59.1412,29.0937 --56.1882,31.7918 --58.8236,28.6946 --55.5346,30.9711 --56.1882,31.7918 --59.1412,29.0937 --58.8236,28.6946 --55.5346,30.9711 --58.5683,28.269 --55.0119,30.0999 --55.5346,30.9711 --58.8236,28.6946 --58.5683,28.269 --55.0119,30.0999 --58.3702,27.814 --54.6065,29.1683 --55.0119,30.0999 --58.5683,28.269 --58.3702,27.814 --54.6065,29.1683 --58.2329,27.337 --54.3253,28.1921 --54.6065,29.1683 --58.3702,27.814 --58.2329,27.337 --54.3253,28.1921 --58.1585,26.8463 --54.1731,27.1876 --54.3253,28.1921 --58.2329,27.337 --58.1585,26.8463 --54.1731,27.1876 --58.1444,24.991 --54.1444,24.9914 --54.1731,27.1876 --58.1585,26.8463 --58.1444,24.991 --54.1444,24.9914 --58.1444,24.361 --54.1444,24.3614 --54.1444,24.9914 --58.1444,24.991 --58.1444,24.361 --63.2952,34.0032 --61.6852,34.0025 --61.6852,34.0025 --63.2952,34.0032 --63.2952,34.0032 --61.6852,34.0025 --61.6852,34.0025 --60.6563,33.9803 --60.6563,33.9803 --61.6852,34.0025 --61.6852,34.0025 --60.6563,33.9803 --60.6563,33.9803 --59.6508,33.8227 --59.6508,33.8227 --60.6563,33.9803 --60.6563,33.9803 --59.6508,33.8227 --59.6508,33.8227 --58.6801,33.5166 --58.6801,33.5166 --59.6508,33.8227 --59.6508,33.8227 --58.6801,33.5166 --58.6801,33.5166 --57.766,33.0689 --57.766,33.0689 --58.6801,33.5166 --58.6801,33.5166 --57.766,33.0689 --57.766,33.0689 --56.9292,32.4896 --56.9292,32.4896 --57.766,33.0689 --57.766,33.0689 --56.9292,32.4896 --56.9292,32.4896 --56.1882,31.7918 --56.1882,31.7918 --56.9292,32.4896 --56.9292,32.4896 --56.1882,31.7918 --56.1882,31.7918 --55.5346,30.9711 --55.5346,30.9711 --56.1882,31.7918 --56.1882,31.7918 --55.5346,30.9711 --55.5346,30.9711 --55.0119,30.0999 --55.0119,30.0999 --55.5346,30.9711 --55.5346,30.9711 --55.0119,30.0999 --55.0119,30.0999 --54.6065,29.1683 --54.6065,29.1683 --55.0119,30.0999 --55.0119,30.0999 --54.6065,29.1683 --54.6065,29.1683 --54.3253,28.1921 --54.3253,28.1921 --54.6065,29.1683 --54.6065,29.1683 --54.3253,28.1921 --54.3253,28.1921 --54.1731,27.1876 --54.1731,27.1876 --54.3253,28.1921 --54.3253,28.1921 --54.1731,27.1876 --54.1731,27.1876 --54.1444,24.9914 --54.1444,24.9914 --54.1731,27.1876 --54.1731,27.1876 --54.1444,24.9914 --54.1444,24.9914 --54.1444,24.3614 --54.1444,24.3614 --54.1444,24.9914 --54.1444,24.9914 --54.1444,24.3614 --54.1444,24.3614 --50.1445,25.5017 --54.1445,25.5014 --54.1444,24.3614 --50.1444,24.3617 --50.1445,25.5017 --54.1445,25.5014 --50.1974,26.932 --54.1812,26.5721 --54.1445,25.5014 --50.1445,25.5017 --50.1974,26.932 --54.1812,26.5721 --50.4315,28.4799 --54.3436,27.6458 --54.1812,26.5721 --50.1974,26.932 --50.4315,28.4799 --54.3436,27.6458 --50.8492,29.9888 --54.6333,28.6923 --54.3436,27.6458 --50.4315,28.4799 --50.8492,29.9888 --54.6333,28.6923 --51.4446,31.4367 --55.0462,29.6966 --54.6333,28.6923 --50.8492,29.9888 --51.4446,31.4367 --55.0462,29.6966 --52.209,32.803 --55.5764,30.6442 --55.0462,29.6966 --51.4446,31.4367 --52.209,32.803 --55.5764,30.6442 --53.1034,34.0339 --56.1968,31.4979 --55.5764,30.6442 --52.209,32.803 --53.1034,34.0339 --56.1968,31.4979 --54.2248,35.2098 --56.9045,32.24 --56.1968,31.4979 --53.1034,34.0339 --54.2248,35.2098 --56.9045,32.24 --55.5094,36.2048 --57.7152,32.868 --56.9045,32.24 --54.2248,35.2098 --55.5094,36.2048 --57.7152,32.868 --56.9282,36.9968 --58.6106,33.3678 --57.7152,32.868 --55.5094,36.2048 --56.9282,36.9968 --58.6106,33.3678 --58.4495,37.5678 --59.5706,33.7281 --58.6106,33.3678 --56.9282,36.9968 --58.4495,37.5678 --59.5706,33.7281 --60.039,37.9051 --60.5737,33.941 --59.5706,33.7281 --58.4495,37.5678 --60.039,37.9051 --60.5737,33.941 --61.5834,38.0025 --61.5852,34.0025 --60.5737,33.941 --60.039,37.9051 --61.5834,38.0025 --61.5852,34.0025 --63.2934,38.0032 --63.2952,34.0032 --61.5852,34.0025 --61.5834,38.0025 --63.2934,38.0032 --54.1444,24.3614 --54.1445,25.5014 --54.1445,25.5014 --54.1444,24.3614 --54.1444,24.3614 --54.1445,25.5014 --54.1445,25.5014 --54.1812,26.5721 --54.1812,26.5721 --54.1445,25.5014 --54.1445,25.5014 --54.1812,26.5721 --54.1812,26.5721 --54.3436,27.6458 --54.3436,27.6458 --54.1812,26.5721 --54.1812,26.5721 --54.3436,27.6458 --54.3436,27.6458 --54.6333,28.6923 --54.6333,28.6923 --54.3436,27.6458 --54.3436,27.6458 --54.6333,28.6923 --54.6333,28.6923 --55.0462,29.6966 --55.0462,29.6966 --54.6333,28.6923 --54.6333,28.6923 --55.0462,29.6966 --55.0462,29.6966 --55.5764,30.6442 --55.5764,30.6442 --55.0462,29.6966 --55.0462,29.6966 --55.5764,30.6442 --55.5764,30.6442 --56.1968,31.4979 --56.1968,31.4979 --55.5764,30.6442 --55.5764,30.6442 --56.1968,31.4979 --56.1968,31.4979 --56.9045,32.24 --56.9045,32.24 --56.1968,31.4979 --56.1968,31.4979 --56.9045,32.24 --56.9045,32.24 --57.7152,32.868 --57.7152,32.868 --56.9045,32.24 --56.9045,32.24 --57.7152,32.868 --57.7152,32.868 --58.6106,33.3678 --58.6106,33.3678 --57.7152,32.868 --57.7152,32.868 --58.6106,33.3678 --58.6106,33.3678 --59.5706,33.7281 --59.5706,33.7281 --58.6106,33.3678 --58.6106,33.3678 --59.5706,33.7281 --59.5706,33.7281 --60.5737,33.941 --60.5737,33.941 --59.5706,33.7281 --59.5706,33.7281 --60.5737,33.941 --60.5737,33.941 --61.5852,34.0025 --61.5852,34.0025 --60.5737,33.941 --60.5737,33.941 --61.5852,34.0025 --61.5852,34.0025 --63.2952,34.0032 --63.2952,34.0032 --61.5852,34.0025 --61.5852,34.0025 --63.2952,34.0032 -85.389,42.4795 -85.3941,42.5197 -85.3941,42.5197 -85.389,42.4795 -85.389,42.4795 -85.3941,42.5197 -85.3941,42.5197 -85.4089,42.5575 -85.4089,42.5575 -85.3941,42.5197 -85.3941,42.5197 -85.4089,42.5575 -85.4089,42.5575 -85.4326,42.5904 -85.4326,42.5904 -85.4089,42.5575 -85.4089,42.5575 -85.4326,42.5904 -85.4326,42.5904 -85.2739,42.4658 -85.2739,42.4658 -85.4326,42.5904 -85.4326,42.5904 -85.2739,42.4658 -85.2739,42.4658 -85.0734,42.3487 -85.0734,42.3487 -85.2739,42.4658 -85.2739,42.4658 -85.0734,42.3487 -85.0734,42.3487 -84.8543,42.2716 -84.8543,42.2716 -85.0734,42.3487 -85.0734,42.3487 -84.8543,42.2716 -84.8543,42.2716 -84.6247,42.2372 -84.6247,42.2372 -84.8543,42.2716 -84.8543,42.2716 -84.6247,42.2372 -84.6247,42.2372 -84.5486,42.2355 -84.5486,42.2355 -84.6247,42.2372 -84.6247,42.2372 -84.5486,42.2355 -85.389,42.4795 -85.3941,42.5197 -89.27,41.531 -85.389,42.4795 -89.27,41.531 -89.389,42.4804 -85.3941,42.5197 -85.4089,42.5575 -88.9197,40.6406 -85.3941,42.5197 -88.9197,40.6406 -89.27,41.531 -85.4089,42.5575 -85.4326,42.5904 -88.36,39.8645 -85.4089,42.5575 -88.36,39.8645 -88.9197,40.6406 -85.4326,42.5904 -85.2739,42.4658 -87.6097,39.2187 -85.4326,42.5904 -87.6097,39.2187 -88.36,39.8645 -85.2739,42.4658 -85.0734,42.3487 -86.7539,38.7189 -85.2739,42.4658 -86.7539,38.7189 -87.6097,39.2187 -85.0734,42.3487 -84.8543,42.2716 -85.8191,38.3897 -85.0734,42.3487 -85.8191,38.3897 -86.7539,38.7189 -84.8543,42.2716 -84.6247,42.2372 -84.839,38.243 -84.8543,42.2716 -84.839,38.243 -85.8191,38.3897 -84.6247,42.2372 -84.5486,42.2355 -84.5467,38.2355 -84.6247,42.2372 -84.5467,38.2355 -84.839,38.243 -89.389,42.4804 -89.27,41.531 -89.5607,41.4568 -89.389,42.4804 -89.5607,41.4568 -89.689,42.4805 -89.27,41.531 -88.9197,40.6406 -89.183,40.4968 -89.27,41.531 -89.183,40.4968 -89.5607,41.4568 -88.9197,40.6406 -88.36,39.8645 -88.5796,39.66 -88.9197,40.6406 -88.5796,39.66 -89.183,40.4968 -88.36,39.8645 -87.6097,39.2187 -87.7849,38.9752 -88.36,39.8645 -87.7849,38.9752 -88.5796,39.66 -87.6097,39.2187 -86.7539,38.7189 -86.8799,38.4466 -87.6097,39.2187 -86.8799,38.4466 -87.7849,38.9752 -86.7539,38.7189 -85.8191,38.3897 -85.8914,38.0985 -86.7539,38.7189 -85.8914,38.0985 -86.8799,38.4466 -85.8191,38.3897 -84.839,38.243 -84.855,37.9434 -85.8191,38.3897 -84.855,37.9434 -85.8914,38.0985 -84.839,38.243 -84.5467,38.2355 -84.5466,37.9355 -84.839,38.243 -84.5466,37.9355 -84.855,37.9434 -84.5448,33.9355 -85.5948,33.935 -85.5948,33.935 -84.5448,33.9355 -84.5448,33.9355 -85.5948,33.935 -85.5948,33.935 -87.9405,33.9339 -87.9405,33.9339 -85.5948,33.935 -85.5948,33.935 -87.9405,33.9339 -87.9405,33.9339 -88.9501,34.0144 -88.9501,34.0144 -87.9405,33.9339 -87.9405,33.9339 -88.9501,34.0144 -88.9501,34.0144 -89.934,34.2547 -89.934,34.2547 -88.9501,34.0144 -88.9501,34.0144 -89.934,34.2547 -89.934,34.2547 -90.8559,34.6429 -90.8559,34.6429 -89.934,34.2547 -89.934,34.2547 -90.8559,34.6429 -90.8559,34.6429 -91.7255,35.1863 -91.7255,35.1863 -90.8559,34.6429 -90.8559,34.6429 -91.7255,35.1863 -91.7255,35.1863 -92.4894,35.878 -92.4894,35.878 -91.7255,35.1863 -91.7255,35.1863 -92.4894,35.878 -92.4894,35.878 -93.0919,36.7256 -93.0919,36.7256 -92.4894,35.878 -92.4894,35.878 -93.0919,36.7256 -93.0919,36.7256 -93.4948,37.6843 -93.4948,37.6843 -93.0919,36.7256 -93.0919,36.7256 -93.4948,37.6843 -93.4948,37.6843 -93.6789,38.7078 -93.6789,38.7078 -93.4948,37.6843 -93.4948,37.6843 -93.6789,38.7078 -93.6789,38.7078 -93.6896,40.1914 -93.6896,40.1914 -93.6789,38.7078 -93.6789,38.7078 -93.6896,40.1914 -93.6896,40.1914 -93.6893,41.2314 -93.6893,41.2314 -93.6896,40.1914 -93.6896,40.1914 -93.6893,41.2314 -93.6893,41.2314 -93.689,42.4814 -93.689,42.4814 -93.6893,41.2314 -93.6893,41.2314 -93.689,42.4814 -84.5448,33.9355 -85.5948,33.935 -85.5966,37.935 -84.5448,33.9355 -85.5966,37.935 -84.5466,37.9355 -85.5948,33.935 -87.9405,33.9339 -87.9423,37.9339 -85.5948,33.935 -87.9423,37.9339 -85.5966,37.935 -87.9405,33.9339 -88.9501,34.0144 -88.3147,37.9636 -87.9405,33.9339 -88.3147,37.9636 -87.9423,37.9339 -88.9501,34.0144 -89.934,34.2547 -88.6775,38.0522 -88.9501,34.0144 -88.6775,38.0522 -88.3147,37.9636 -89.934,34.2547 -90.8559,34.6429 -89.0175,38.1954 -89.934,34.2547 -89.0175,38.1954 -88.6775,38.0522 -90.8559,34.6429 -91.7255,35.1863 -89.3382,38.3958 -90.8559,34.6429 -89.3382,38.3958 -89.0175,38.1954 -91.7255,35.1863 -92.4894,35.878 -89.5032,38.5393 -91.7255,35.1863 -89.5032,38.5393 -89.3382,38.3958 -92.4894,35.878 -93.0919,36.7256 -89.5968,38.6711 -92.4894,35.878 -89.5968,38.6711 -89.5032,38.5393 -93.0919,36.7256 -93.4948,37.6843 -89.6595,38.8202 -93.0919,36.7256 -89.6595,38.8202 -89.5968,38.6711 -93.4948,37.6843 -93.6789,38.7078 -89.6881,38.9793 -93.4948,37.6843 -89.6881,38.9793 -89.6595,38.8202 -93.6789,38.7078 -93.6896,40.1914 -89.6896,40.1905 -93.6789,38.7078 -89.6896,40.1905 -89.6881,38.9793 -93.6896,40.1914 -93.6893,41.2314 -89.6893,41.2305 -93.6896,40.1914 -89.6893,41.2305 -89.6896,40.1905 -93.6893,41.2314 -93.689,42.4814 -89.689,42.4805 -93.6893,41.2314 -89.689,42.4805 -89.6893,41.2305 -84.5448,33.9355 -85.5929,29.935 -85.5948,33.935 -84.5448,33.9355 -84.5429,29.9355 -85.5929,29.935 -85.5948,33.935 -87.5377,29.9341 -87.5395,33.9341 -85.5948,33.935 -85.5929,29.935 -87.5377,29.9341 -87.5395,33.9341 -89.0142,30.0221 -88.5371,33.9936 -87.5395,33.9341 -87.5377,29.9341 -89.0142,30.0221 -88.5371,33.9936 -90.4695,30.2863 -89.5205,34.172 -88.5371,33.9936 -89.0142,30.0221 -90.4695,30.2863 -89.5205,34.172 -91.8828,30.7227 -90.4754,34.467 -89.5205,34.172 -90.4695,30.2863 -91.8828,30.7227 -90.4754,34.467 -93.2336,31.3252 -91.3881,34.874 -90.4754,34.467 -91.8828,30.7227 -93.2336,31.3252 -91.3881,34.874 -94.7978,32.3381 -92.2575,35.4279 -91.3881,34.874 -93.2336,31.3252 -94.7978,32.3381 -92.2575,35.4279 -96.1904,33.821 -92.9472,36.1624 -92.2575,35.4279 -94.7978,32.3381 -96.1904,33.821 -92.9472,36.1624 -97.1744,35.6483 -93.4346,37.0674 -92.9472,36.1624 -96.1904,33.821 -97.1744,35.6483 -93.4346,37.0674 -97.6482,37.6477 -93.6693,38.0577 -93.4346,37.0674 -97.1744,35.6483 -97.6482,37.6477 -93.6693,38.0577 -97.6897,39.5023 -93.6897,39.5014 -93.6693,38.0577 -97.6482,37.6477 -97.6897,39.5023 -93.6897,39.5014 -97.6894,40.9523 -93.6894,40.9514 -93.6897,39.5014 -97.6897,39.5023 -97.6894,40.9523 -93.6894,40.9514 -97.689,42.4823 -93.689,42.4814 -93.6894,40.9514 -97.6894,40.9523 -97.689,42.4823 -84.5448,33.9355 -85.5948,33.935 -85.5948,33.935 -84.5448,33.9355 -84.5448,33.9355 -85.5948,33.935 -85.5948,33.935 -87.5395,33.9341 -87.5395,33.9341 -85.5948,33.935 -85.5948,33.935 -87.5395,33.9341 -87.5395,33.9341 -88.5371,33.9936 -88.5371,33.9936 -87.5395,33.9341 -87.5395,33.9341 -88.5371,33.9936 -88.5371,33.9936 -89.5205,34.172 -89.5205,34.172 -88.5371,33.9936 -88.5371,33.9936 -89.5205,34.172 -89.5205,34.172 -90.4754,34.467 -90.4754,34.467 -89.5205,34.172 -89.5205,34.172 -90.4754,34.467 -90.4754,34.467 -91.3881,34.874 -91.3881,34.874 -90.4754,34.467 -90.4754,34.467 -91.3881,34.874 -91.3881,34.874 -92.2575,35.4279 -92.2575,35.4279 -91.3881,34.874 -91.3881,34.874 -92.2575,35.4279 -92.2575,35.4279 -92.9472,36.1624 -92.9472,36.1624 -92.2575,35.4279 -92.2575,35.4279 -92.9472,36.1624 -92.9472,36.1624 -93.4346,37.0674 -93.4346,37.0674 -92.9472,36.1624 -92.9472,36.1624 -93.4346,37.0674 -93.4346,37.0674 -93.6693,38.0577 -93.6693,38.0577 -93.4346,37.0674 -93.4346,37.0674 -93.6693,38.0577 -93.6693,38.0577 -93.6897,39.5014 -93.6897,39.5014 -93.6693,38.0577 -93.6693,38.0577 -93.6897,39.5014 -93.6897,39.5014 -93.6894,40.9514 -93.6894,40.9514 -93.6897,39.5014 -93.6897,39.5014 -93.6894,40.9514 -93.6894,40.9514 -93.689,42.4814 -93.689,42.4814 -93.6894,40.9514 -93.6894,40.9514 -93.689,42.4814 -97.9931,24.4824 -101.993,26.2033 -97.9927,26.2024 -97.9931,24.4824 -101.993,24.4833 -101.993,26.2033 -97.9927,26.2024 -101.991,31.7508 -97.9915,31.7499 -97.9927,26.2024 -101.993,26.2033 -101.991,31.7508 -97.9915,31.7499 -101.991,33.6933 -97.991,33.6924 -97.9915,31.7499 -101.991,31.7508 -101.991,33.6933 -97.991,33.6924 -101.99,39.5033 -97.9897,39.5024 -97.991,33.6924 -101.991,33.6933 -101.99,39.5033 -97.9897,39.5024 -101.989,40.9533 -97.9894,40.9524 -97.9897,39.5024 -101.99,39.5033 -101.989,40.9533 -97.9894,40.9524 -101.989,42.4833 -97.989,42.4824 -97.9894,40.9524 -101.989,40.9533 -101.989,42.4833 -97.6931,24.4823 -97.9927,26.2024 -97.6927,26.2023 -97.6931,24.4823 -97.9931,24.4824 -97.9927,26.2024 -97.6927,26.2023 -97.9915,31.7499 -97.6915,31.7498 -97.6927,26.2023 -97.9927,26.2024 -97.9915,31.7499 -97.6915,31.7498 -97.991,33.6924 -97.691,33.6923 -97.6915,31.7498 -97.9915,31.7499 -97.991,33.6924 -97.691,33.6923 -97.9897,39.5024 -97.6897,39.5023 -97.691,33.6923 -97.991,33.6924 -97.9897,39.5024 -97.6897,39.5023 -97.9894,40.9524 -97.6894,40.9523 -97.6897,39.5023 -97.9897,39.5024 -97.9894,40.9524 -97.6894,40.9523 -97.989,42.4824 -97.689,42.4823 -97.6894,40.9523 -97.9894,40.9524 -97.989,42.4824 -93.6931,24.4814 -97.6927,26.2023 -93.6927,26.2014 -93.6931,24.4814 -97.6931,24.4823 -97.6927,26.2023 -93.6927,26.2014 -97.6915,31.7498 -93.6915,31.7489 -93.6927,26.2014 -97.6927,26.2023 -97.6915,31.7498 -93.6915,31.7489 -97.691,33.6923 -93.691,33.6914 -93.6915,31.7489 -97.6915,31.7498 -97.691,33.6923 -93.691,33.6914 -97.6897,39.5023 -93.6897,39.5014 -93.691,33.6914 -97.691,33.6923 -97.6897,39.5023 -93.6897,39.5014 -97.6894,40.9523 -93.6894,40.9514 -93.6897,39.5014 -97.6897,39.5023 -97.6894,40.9523 -93.6894,40.9514 -97.689,42.4823 -93.689,42.4814 -93.6894,40.9514 -97.6894,40.9523 -97.689,42.4823 -93.6931,24.4814 -93.6927,26.2014 -93.6927,26.2014 -93.6931,24.4814 -93.6931,24.4814 -93.6927,26.2014 -93.6927,26.2014 -93.6915,31.7489 -93.6915,31.7489 -93.6927,26.2014 -93.6927,26.2014 -93.6915,31.7489 -93.6915,31.7489 -93.691,33.6914 -93.691,33.6914 -93.6915,31.7489 -93.6915,31.7489 -93.691,33.6914 -93.691,33.6914 -93.6897,39.5014 -93.6897,39.5014 -93.691,33.6914 -93.691,33.6914 -93.6897,39.5014 -93.6897,39.5014 -93.6894,40.9514 -93.6894,40.9514 -93.6897,39.5014 -93.6897,39.5014 -93.6894,40.9514 -93.6894,40.9514 -93.689,42.4814 -93.689,42.4814 -93.6894,40.9514 -93.6894,40.9514 -93.689,42.4814 -93.6931,24.4814 -93.6927,26.2014 -93.6927,26.2014 -93.6931,24.4814 -93.6931,24.4814 -93.6927,26.2014 -93.6927,26.2014 -93.6915,31.7489 -93.6915,31.7489 -93.6927,26.2014 -93.6927,26.2014 -93.6915,31.7489 -93.6915,31.7489 -93.691,33.6914 -93.691,33.6914 -93.6915,31.7489 -93.6915,31.7489 -93.691,33.6914 -93.691,33.6914 -93.6897,39.5014 -93.6897,39.5014 -93.691,33.6914 -93.691,33.6914 -93.6897,39.5014 -93.6897,39.5014 -93.6894,40.9514 -93.6894,40.9514 -93.6897,39.5014 -93.6897,39.5014 -93.6894,40.9514 -93.6894,40.9514 -93.689,42.4814 -93.689,42.4814 -93.6894,40.9514 -93.6894,40.9514 -93.689,42.4814 -93.6931,24.4814 -93.6927,26.2014 -89.6927,26.2005 -93.6931,24.4814 -89.6927,26.2005 -89.6931,24.4805 -93.6927,26.2014 -93.6915,31.7489 -89.6915,31.748 -93.6927,26.2014 -89.6915,31.748 -89.6927,26.2005 -93.6915,31.7489 -93.691,33.6914 -89.691,33.6905 -93.6915,31.7489 -89.691,33.6905 -89.6915,31.748 -93.691,33.6914 -93.6897,39.5014 -89.6897,39.5005 -93.691,33.6914 -89.6897,39.5005 -89.691,33.6905 -93.6897,39.5014 -93.6894,40.9514 -89.6894,40.9505 -93.6897,39.5014 -89.6894,40.9505 -89.6897,39.5005 -93.6894,40.9514 -93.689,42.4814 -89.689,42.4805 -93.6894,40.9514 -89.689,42.4805 -89.6894,40.9505 -84.5448,33.9355 -85.5929,29.935 -85.5948,33.935 -84.5448,33.9355 -84.5429,29.9355 -85.5929,29.935 -85.5948,33.935 -86.4773,29.9316 -86.6391,33.9283 -85.5948,33.935 -85.5929,29.935 -86.4773,29.9316 -86.6391,33.9283 -86.9597,29.8805 -87.6382,33.8226 -86.6391,33.9283 -86.4773,29.9316 -86.9597,29.8805 -87.6382,33.8226 -87.4314,29.7674 -88.6152,33.5882 -87.6382,33.8226 -86.9597,29.8805 -87.4314,29.7674 -88.6152,33.5882 -87.8844,29.594 -89.5535,33.2291 -88.6152,33.5882 -87.4314,29.7674 -87.8844,29.594 -89.5535,33.2291 -88.3111,29.3634 -90.4374,32.7515 -89.5535,33.2291 -87.8844,29.594 -88.3111,29.3634 -90.4374,32.7515 -88.7044,29.0794 -91.2519,32.1632 -90.4374,32.7515 -88.3111,29.3634 -88.7044,29.0794 -91.2519,32.1632 -89.0234,28.7762 -92.0047,31.4429 -91.2519,32.1632 -88.7044,29.0794 -89.0234,28.7762 -92.0047,31.4429 -89.2774,28.4418 -92.6456,30.5995 -92.0047,31.4429 -89.0234,28.7762 -89.2774,28.4418 -92.6456,30.5995 -89.475,28.0711 -93.1439,29.6647 -92.6456,30.5995 -89.2774,28.4418 -89.475,28.0711 -93.1439,29.6647 -89.611,27.6738 -93.4869,28.6624 -93.1439,29.6647 -89.475,28.0711 -89.611,27.6738 -93.4869,28.6624 -89.682,27.2598 -93.6659,27.6184 -93.4869,28.6624 -89.611,27.6738 -89.682,27.2598 -93.6659,27.6184 -89.6927,26.3905 -93.6927,26.3914 -93.6659,27.6184 -89.682,27.2598 -89.6927,26.3905 -93.6927,26.3914 -89.6931,24.4805 -93.6931,24.4814 -93.6927,26.3914 -89.6927,26.3905 -89.6931,24.4805 -84.5448,33.9355 -85.5948,33.935 -85.5948,33.935 -84.5448,33.9355 -84.5448,33.9355 -85.5948,33.935 -85.5948,33.935 -86.6391,33.9283 -86.6391,33.9283 -85.5948,33.935 -85.5948,33.935 -86.6391,33.9283 -86.6391,33.9283 -87.6382,33.8226 -87.6382,33.8226 -86.6391,33.9283 -86.6391,33.9283 -87.6382,33.8226 -87.6382,33.8226 -88.6152,33.5882 -88.6152,33.5882 -87.6382,33.8226 -87.6382,33.8226 -88.6152,33.5882 -88.6152,33.5882 -89.5535,33.2291 -89.5535,33.2291 -88.6152,33.5882 -88.6152,33.5882 -89.5535,33.2291 -89.5535,33.2291 -90.4374,32.7515 -90.4374,32.7515 -89.5535,33.2291 -89.5535,33.2291 -90.4374,32.7515 -90.4374,32.7515 -91.2519,32.1632 -91.2519,32.1632 -90.4374,32.7515 -90.4374,32.7515 -91.2519,32.1632 -91.2519,32.1632 -92.0047,31.4429 -92.0047,31.4429 -91.2519,32.1632 -91.2519,32.1632 -92.0047,31.4429 -92.0047,31.4429 -92.6456,30.5995 -92.6456,30.5995 -92.0047,31.4429 -92.0047,31.4429 -92.6456,30.5995 -92.6456,30.5995 -93.1439,29.6647 -93.1439,29.6647 -92.6456,30.5995 -92.6456,30.5995 -93.1439,29.6647 -93.1439,29.6647 -93.4869,28.6624 -93.4869,28.6624 -93.1439,29.6647 -93.1439,29.6647 -93.4869,28.6624 -93.4869,28.6624 -93.6659,27.6184 -93.6659,27.6184 -93.4869,28.6624 -93.4869,28.6624 -93.6659,27.6184 -93.6659,27.6184 -93.6927,26.3914 -93.6927,26.3914 -93.6659,27.6184 -93.6659,27.6184 -93.6927,26.3914 -93.6927,26.3914 -93.6931,24.4814 -93.6931,24.4814 -93.6927,26.3914 -93.6927,26.3914 -93.6931,24.4814 -93.6931,24.4814 -97.6927,26.2023 -93.6927,26.2014 -93.6931,24.4814 -97.6931,24.4823 -97.6927,26.2023 -93.6927,26.2014 -97.6568,27.5512 -93.6697,27.2307 -93.6927,26.2014 -97.6927,26.2023 -97.6568,27.5512 -93.6697,27.2307 -97.3991,29.1982 -93.5047,28.2854 -93.6697,27.2307 -97.6568,27.5512 -97.3991,29.1982 -93.5047,28.2854 -96.8982,30.7882 -93.1838,29.3037 -93.5047,28.2854 -97.3991,29.1982 -96.8982,30.7882 -93.1838,29.3037 -96.1652,32.2854 -92.7145,30.2625 -93.1838,29.3037 -96.8982,30.7882 -96.1652,32.2854 -92.7145,30.2625 -95.2168,33.6563 -92.1071,31.1405 -92.7145,30.2625 -96.1652,32.2854 -95.2168,33.6563 -92.1071,31.1405 -94.1952,34.7665 -91.4104,31.895 -92.1071,31.1405 -95.2168,33.6563 -94.1952,34.7665 -91.4104,31.895 -92.9938,35.7785 -90.637,32.5465 -91.4104,31.895 -94.1952,34.7665 -92.9938,35.7785 -90.637,32.5465 -91.663,36.613 -89.7803,33.0838 -90.637,32.5465 -92.9938,35.7785 -91.663,36.613 -89.7803,33.0838 -90.2288,37.2536 -88.8569,33.4962 -89.7803,33.0838 -91.663,36.613 -90.2288,37.2536 -88.8569,33.4962 -88.7192,37.6878 -87.8851,33.7757 -88.8569,33.4962 -90.2288,37.2536 -88.7192,37.6878 -87.8851,33.7757 -87.1638,37.9071 -86.8837,33.9169 -87.8851,33.7757 -88.7192,37.6878 -87.1638,37.9071 -86.8837,33.9169 -85.5966,37.935 -85.5948,33.935 -86.8837,33.9169 -87.1638,37.9071 -85.5966,37.935 -85.5948,33.935 -84.5566,37.9355 -84.5548,33.9355 -85.5948,33.935 -85.5966,37.935 -84.5566,37.9355 -84.5548,33.9355 -84.5466,37.9355 -84.5448,33.9355 -84.5548,33.9355 -84.5566,37.9355 -84.5466,37.9355 -93.6931,24.4814 -93.6927,26.2014 -93.6927,26.2014 -93.6931,24.4814 -93.6931,24.4814 -93.6927,26.2014 -93.6927,26.2014 -93.6697,27.2307 -93.6697,27.2307 -93.6927,26.2014 -93.6927,26.2014 -93.6697,27.2307 -93.6697,27.2307 -93.5047,28.2854 -93.5047,28.2854 -93.6697,27.2307 -93.6697,27.2307 -93.5047,28.2854 -93.5047,28.2854 -93.1838,29.3037 -93.1838,29.3037 -93.5047,28.2854 -93.5047,28.2854 -93.1838,29.3037 -93.1838,29.3037 -92.7145,30.2625 -92.7145,30.2625 -93.1838,29.3037 -93.1838,29.3037 -92.7145,30.2625 -92.7145,30.2625 -92.1071,31.1405 -92.1071,31.1405 -92.7145,30.2625 -92.7145,30.2625 -92.1071,31.1405 -92.1071,31.1405 -91.4104,31.895 -91.4104,31.895 -92.1071,31.1405 -92.1071,31.1405 -91.4104,31.895 -91.4104,31.895 -90.637,32.5465 -90.637,32.5465 -91.4104,31.895 -91.4104,31.895 -90.637,32.5465 -90.637,32.5465 -89.7803,33.0838 -89.7803,33.0838 -90.637,32.5465 -90.637,32.5465 -89.7803,33.0838 -89.7803,33.0838 -88.8569,33.4962 -88.8569,33.4962 -89.7803,33.0838 -89.7803,33.0838 -88.8569,33.4962 -88.8569,33.4962 -87.8851,33.7757 -87.8851,33.7757 -88.8569,33.4962 -88.8569,33.4962 -87.8851,33.7757 -87.8851,33.7757 -86.8837,33.9169 -86.8837,33.9169 -87.8851,33.7757 -87.8851,33.7757 -86.8837,33.9169 -86.8837,33.9169 -85.5948,33.935 -85.5948,33.935 -86.8837,33.9169 -86.8837,33.9169 -85.5948,33.935 -85.5948,33.935 -84.5548,33.9355 -84.5548,33.9355 -85.5948,33.935 -85.5948,33.935 -84.5548,33.9355 -84.5548,33.9355 -84.5448,33.9355 -84.5448,33.9355 -84.5548,33.9355 -84.5548,33.9355 -84.5448,33.9355 -84.541,25.6355 -84.5784,25.6311 -84.5784,25.6311 -84.541,25.6355 -84.541,25.6355 -84.5784,25.6311 -84.5784,25.6311 -84.6139,25.6184 -84.6139,25.6184 -84.5784,25.6311 -84.5784,25.6311 -84.6139,25.6184 -84.6139,25.6184 -84.6455,25.5978 -84.6455,25.5978 -84.6139,25.6184 -84.6139,25.6184 -84.6455,25.5978 -84.6455,25.5978 -85.1291,25.0705 -85.1291,25.0705 -84.6455,25.5978 -84.6455,25.5978 -85.1291,25.0705 -85.1291,25.0705 -85.2743,24.8927 -85.2743,24.8927 -85.1291,25.0705 -85.1291,25.0705 -85.2743,24.8927 -85.2743,24.8927 -85.3433,24.7534 -85.3433,24.7534 -85.2743,24.8927 -85.2743,24.8927 -85.3433,24.7534 -85.3433,24.7534 -85.3832,24.6032 -85.3832,24.6032 -85.3433,24.7534 -85.3433,24.7534 -85.3832,24.6032 -85.3832,24.6032 -85.3931,24.4795 -85.3931,24.4795 -85.3832,24.6032 -85.3832,24.6032 -85.3931,24.4795 -84.541,25.6355 -84.5784,25.6311 -85.4921,29.5254 -84.541,25.6355 -85.4921,29.5254 -84.5428,29.6355 -84.5784,25.6311 -84.6139,25.6184 -86.3913,29.2018 -84.5784,25.6311 -86.3913,29.2018 -85.4921,29.5254 -84.6139,25.6184 -84.6455,25.5978 -87.1931,28.6817 -84.6139,25.6184 -87.1931,28.6817 -86.3913,29.2018 -84.6455,25.5978 -85.1291,25.0705 -88.0835,27.767 -84.6455,25.5978 -88.0835,27.767 -87.1931,28.6817 -85.1291,25.0705 -85.2743,24.8927 -88.6638,27.0166 -85.1291,25.0705 -88.6638,27.0166 -88.0835,27.767 -85.2743,24.8927 -85.3433,24.7534 -89.0872,26.1616 -85.2743,24.8927 -89.0872,26.1616 -88.6638,27.0166 -85.3433,24.7534 -85.3832,24.6032 -89.3322,25.2396 -85.3433,24.7534 -89.3322,25.2396 -89.0872,26.1616 -85.3832,24.6032 -85.3931,24.4795 -89.3931,24.4806 -85.3832,24.6032 -89.3931,24.4806 -89.3322,25.2396 -84.5428,29.6355 -85.4921,29.5254 -85.5606,29.8174 -84.5428,29.6355 -85.5606,29.8174 -84.5429,29.9355 -85.4921,29.5254 -86.3913,29.2018 -86.5246,29.4705 -85.4921,29.5254 -86.5246,29.4705 -85.5606,29.8174 -86.3913,29.2018 -87.1931,28.6817 -87.3842,28.9129 -86.3913,29.2018 -87.3842,28.9129 -86.5246,29.4705 -87.1931,28.6817 -88.0835,27.767 -88.3051,27.9692 -87.1931,28.6817 -88.3051,27.9692 -87.3842,28.9129 -88.0835,27.767 -88.6638,27.0166 -88.918,27.1759 -88.0835,27.767 -88.918,27.1759 -88.3051,27.9692 -88.6638,27.0166 -89.0872,26.1616 -89.368,26.2673 -88.6638,27.0166 -89.368,26.2673 -88.918,27.1759 -89.0872,26.1616 -89.3322,25.2396 -89.6284,25.2873 -89.0872,26.1616 -89.6284,25.2873 -89.368,26.2673 -89.3322,25.2396 -89.3931,24.4806 -89.6931,24.4807 -89.3322,25.2396 -89.6931,24.4807 -89.6284,25.2873 -31.8551,24.4159 -32.061,25.414 -31.7663,25.3577 -31.8551,24.4159 -32.1551,24.4156 -32.061,25.414 -31.7663,25.3577 -31.7799,26.3767 -31.5012,26.2657 -31.7663,25.3577 -32.061,25.414 -31.7799,26.3767 -31.5012,26.2657 -31.3222,27.269 -31.0694,27.1073 -31.5012,26.2657 -31.7799,26.3767 -31.3222,27.269 -31.0694,27.1073 -30.3896,28.4307 -30.1627,28.2344 -31.0694,27.1073 -31.3222,27.269 -30.3896,28.4307 -30.1627,28.2344 -29.6609,29.1137 -29.4824,28.8726 -30.1627,28.2344 -30.3896,28.4307 -29.6609,29.1137 -29.4824,28.8726 -28.7625,29.6252 -28.6463,29.3485 -29.4824,28.8726 -29.6609,29.1137 -28.7625,29.6252 -28.6463,29.3485 -27.7682,29.9084 -27.7212,29.6121 -28.6463,29.3485 -28.7625,29.6252 -27.7682,29.9084 -27.7212,29.6121 -25.1829,29.9627 -25.1828,29.6627 -27.7212,29.6121 -27.7682,29.9084 -25.1829,29.9627 -27.8551,24.4198 -31.7663,25.3577 -27.8375,24.6061 -27.8551,24.4198 -31.8551,24.4159 -31.7663,25.3577 -27.8375,24.6061 -31.5012,26.2657 -27.7851,24.7857 -27.8375,24.6061 -31.7663,25.3577 -31.5012,26.2657 -27.7851,24.7857 -31.0694,27.1073 -27.6997,24.9521 -27.7851,24.7857 -31.5012,26.2657 -31.0694,27.1073 -27.6997,24.9521 -30.1627,28.2344 -27.1379,25.6171 -27.6997,24.9521 -31.0694,27.1073 -30.1627,28.2344 -27.1379,25.6171 -29.4824,28.8726 -27.1016,25.6583 -27.1379,25.6171 -30.1627,28.2344 -29.4824,28.8726 -27.1016,25.6583 -28.6463,29.3485 -27.0979,25.6604 -27.1016,25.6583 -29.4824,28.8726 -28.6463,29.3485 -27.0979,25.6604 -27.7212,29.6121 -27.0938,25.6616 -27.0979,25.6604 -28.6463,29.3485 -27.7212,29.6121 -27.0938,25.6616 -25.1828,29.6627 -25.181,25.6627 -27.0938,25.6616 -27.7212,29.6121 -25.1828,29.6627 -27.8551,24.4198 -27.8375,24.6061 -27.8375,24.6061 -27.8551,24.4198 -27.8551,24.4198 -27.8375,24.6061 -27.8375,24.6061 -27.7851,24.7857 -27.7851,24.7857 -27.8375,24.6061 -27.8375,24.6061 -27.7851,24.7857 -27.7851,24.7857 -27.6997,24.9521 -27.6997,24.9521 -27.7851,24.7857 -27.7851,24.7857 -27.6997,24.9521 -27.6997,24.9521 -27.1379,25.6171 -27.1379,25.6171 -27.6997,24.9521 -27.6997,24.9521 -27.1379,25.6171 -27.1379,25.6171 -27.1016,25.6583 -27.1016,25.6583 -27.1379,25.6171 -27.1379,25.6171 -27.1016,25.6583 -27.1016,25.6583 -27.0979,25.6604 -27.0979,25.6604 -27.1016,25.6583 -27.1016,25.6583 -27.0979,25.6604 -27.0979,25.6604 -27.0938,25.6616 -27.0938,25.6616 -27.0979,25.6604 -27.0979,25.6604 -27.0938,25.6616 -27.0938,25.6616 -25.181,25.6627 -25.181,25.6627 -27.0938,25.6616 -27.0938,25.6616 -25.181,25.6627 -83.5077,111.851 -83.7625,107.842 -84.1591,111.822 -83.5077,111.851 -83.5104,107.851 -83.7625,107.842 -84.1591,111.822 -83.96,107.812 -84.752,111.733 -84.1591,111.822 -83.7625,107.842 -83.96,107.812 -84.752,111.733 -84.1536,107.763 -85.3331,111.585 -84.752,111.733 -83.96,107.812 -84.1536,107.763 -85.3331,111.585 -84.3414,107.694 -85.8965,111.379 -85.3331,111.585 -84.1536,107.763 -84.3414,107.694 -85.8965,111.379 -84.5213,107.607 -86.4366,111.119 -85.8965,111.379 -84.3414,107.694 -84.5213,107.607 -86.4366,111.119 -84.6917,107.503 -86.948,110.806 -86.4366,111.119 -84.5213,107.607 -84.6917,107.503 -86.948,110.806 -84.8508,107.382 -87.4256,110.443 -86.948,110.806 -84.6917,107.503 -84.8508,107.382 -87.4256,110.443 -84.9928,107.25 -87.8682,110.031 -87.4256,110.443 -84.8508,107.382 -84.9928,107.25 -87.8682,110.031 -85.1087,107.117 -88.272,109.565 -87.8682,110.031 -84.9928,107.25 -85.1087,107.117 -88.272,109.565 -85.2092,106.971 -88.6221,109.057 -88.272,109.565 -85.1087,107.117 -85.2092,106.971 -88.6221,109.057 -85.2931,106.815 -88.9144,108.514 -88.6221,109.057 -85.2092,106.971 -85.2931,106.815 -88.9144,108.514 -85.3594,106.651 -89.1453,107.942 -88.9144,108.514 -85.2931,106.815 -85.3594,106.651 -89.1453,107.942 -85.4073,106.48 -89.312,107.348 -89.1453,107.942 -85.3594,106.651 -85.4073,106.48 -89.312,107.348 -85.4361,106.305 -89.4125,106.739 -89.312,107.348 -85.4073,106.48 -85.4361,106.305 -89.4125,106.739 -85.4456,106.129 -89.4456,106.123 -89.4125,106.739 -85.4361,106.305 -85.4456,106.129 -89.4456,106.123 -85.4448,105.513 -89.4448,105.508 -89.4456,106.123 -85.4456,106.129 -85.4448,105.513 -83.5075,112.151 -84.1591,111.822 -84.1888,112.12 -83.5075,112.151 -83.5077,111.851 -84.1591,111.822 -84.1888,112.12 -84.752,111.733 -84.8114,112.027 -84.1888,112.12 -84.1591,111.822 -84.752,111.733 -84.8114,112.027 -85.3331,111.585 -85.4216,111.871 -84.8114,112.027 -84.752,111.733 -85.3331,111.585 -85.4216,111.871 -85.8965,111.379 -86.0132,111.656 -85.4216,111.871 -85.3331,111.585 -85.8965,111.379 -86.0132,111.656 -86.4366,111.119 -86.5803,111.382 -86.0132,111.656 -85.8965,111.379 -86.4366,111.119 -86.5803,111.382 -86.948,110.806 -87.1173,111.054 -86.5803,111.382 -86.4366,111.119 -86.948,110.806 -87.1173,111.054 -87.4256,110.443 -87.6187,110.673 -87.1173,111.054 -86.948,110.806 -87.4256,110.443 -87.6187,110.673 -87.8682,110.031 -88.0839,110.24 -87.6187,110.673 -87.4256,110.443 -87.8682,110.031 -88.0839,110.24 -88.272,109.565 -88.5092,109.748 -88.0839,110.24 -87.8682,110.031 -88.272,109.565 -88.5092,109.748 -88.6221,109.057 -88.8781,109.213 -88.5092,109.748 -88.272,109.565 -88.6221,109.057 -88.8781,109.213 -88.9144,108.514 -89.186,108.641 -88.8781,109.213 -88.6221,109.057 -88.9144,108.514 -89.186,108.641 -89.1453,107.942 -89.4293,108.039 -89.186,108.641 -88.9144,108.514 -89.1453,107.942 -89.4293,108.039 -89.312,107.348 -89.6049,107.413 -89.4293,108.039 -89.1453,107.942 -89.312,107.348 -89.6049,107.413 -89.4125,106.739 -89.7108,106.772 -89.6049,107.413 -89.312,107.348 -89.4125,106.739 -89.7108,106.772 -89.4456,106.123 -89.7456,106.123 -89.7108,106.772 -89.4125,106.739 -89.4456,106.123 -89.7456,106.123 -89.4448,105.508 -89.7448,105.507 -89.7456,106.123 -89.4456,106.123 -89.4448,105.508 -83.5048,116.151 -84.1888,112.12 -84.5855,116.101 -83.5048,116.151 -83.5075,112.151 -84.1888,112.12 -84.5855,116.101 -84.8114,112.027 -85.6035,115.948 -84.5855,116.101 -84.1888,112.12 -84.8114,112.027 -85.6035,115.948 -85.4216,111.871 -86.6011,115.694 -85.6035,115.948 -84.8114,112.027 -85.4216,111.871 -86.6011,115.694 -86.0132,111.656 -87.5683,115.341 -86.6011,115.694 -85.4216,111.871 -86.0132,111.656 -87.5683,115.341 -86.5803,111.382 -88.4956,114.894 -87.5683,115.341 -86.0132,111.656 -86.5803,111.382 -88.4956,114.894 -87.1173,111.054 -89.3736,114.357 -88.4956,114.894 -86.5803,111.382 -87.1173,111.054 -89.3736,114.357 -87.6187,110.673 -90.1935,113.734 -89.3736,114.357 -87.1173,111.054 -87.6187,110.673 -90.1935,113.734 -88.0839,110.24 -90.9592,113.02 -90.1935,113.734 -87.6187,110.673 -88.0839,110.24 -90.9592,113.02 -88.5092,109.748 -91.6725,112.197 -90.9592,113.02 -88.0839,110.24 -88.5092,109.748 -91.6725,112.197 -88.8781,109.213 -92.291,111.3 -91.6725,112.197 -88.5092,109.748 -88.8781,109.213 -92.291,111.3 -89.186,108.641 -92.8073,110.34 -92.291,111.3 -88.8781,109.213 -89.186,108.641 -92.8073,110.34 -89.4293,108.039 -93.2152,109.33 -92.8073,110.34 -89.186,108.641 -89.4293,108.039 -93.2152,109.33 -89.6049,107.413 -93.5097,108.281 -93.2152,109.33 -89.4293,108.039 -89.6049,107.413 -93.5097,108.281 -89.7108,106.772 -93.6872,107.206 -93.5097,108.281 -89.6049,107.413 -89.7108,106.772 -93.6872,107.206 -89.7456,106.123 -93.7456,106.118 -93.6872,107.206 -89.7108,106.772 -89.7456,106.123 -93.7456,106.118 -89.7448,105.507 -93.7448,105.502 -93.7456,106.118 -89.7456,106.123 -89.7448,105.507 -83.5048,116.151 -84.5855,116.101 -84.5855,116.101 -83.5048,116.151 -83.5048,116.151 -84.5855,116.101 -84.5855,116.101 -85.6035,115.948 -85.6035,115.948 -84.5855,116.101 -84.5855,116.101 -85.6035,115.948 -85.6035,115.948 -86.6011,115.694 -86.6011,115.694 -85.6035,115.948 -85.6035,115.948 -86.6011,115.694 -86.6011,115.694 -87.5683,115.341 -87.5683,115.341 -86.6011,115.694 -86.6011,115.694 -87.5683,115.341 -87.5683,115.341 -88.4956,114.894 -88.4956,114.894 -87.5683,115.341 -87.5683,115.341 -88.4956,114.894 -88.4956,114.894 -89.3736,114.357 -89.3736,114.357 -88.4956,114.894 -88.4956,114.894 -89.3736,114.357 -89.3736,114.357 -90.1935,113.734 -90.1935,113.734 -89.3736,114.357 -89.3736,114.357 -90.1935,113.734 -90.1935,113.734 -90.9592,113.02 -90.9592,113.02 -90.1935,113.734 -90.1935,113.734 -90.9592,113.02 -90.9592,113.02 -91.6725,112.197 -91.6725,112.197 -90.9592,113.02 -90.9592,113.02 -91.6725,112.197 -91.6725,112.197 -92.291,111.3 -92.291,111.3 -91.6725,112.197 -91.6725,112.197 -92.291,111.3 -92.291,111.3 -92.8073,110.34 -92.8073,110.34 -92.291,111.3 -92.291,111.3 -92.8073,110.34 -92.8073,110.34 -93.2152,109.33 -93.2152,109.33 -92.8073,110.34 -92.8073,110.34 -93.2152,109.33 -93.2152,109.33 -93.5097,108.281 -93.5097,108.281 -93.2152,109.33 -93.2152,109.33 -93.5097,108.281 -93.5097,108.281 -93.6872,107.206 -93.6872,107.206 -93.5097,108.281 -93.5097,108.281 -93.6872,107.206 -93.6872,107.206 -93.7456,106.118 -93.7456,106.118 -93.6872,107.206 -93.6872,107.206 -93.7456,106.118 -93.7456,106.118 -93.7448,105.502 -93.7448,105.502 -93.7456,106.118 -93.7456,106.118 -93.7448,105.502 -83.5048,116.151 -84.5855,116.101 -84.9821,120.081 -83.5048,116.151 -84.9821,120.081 -83.5021,120.151 -84.5855,116.101 -85.6035,115.948 -86.3955,119.868 -84.5855,116.101 -86.3955,119.868 -84.9821,120.081 -85.6035,115.948 -86.6011,115.694 -87.7806,119.516 -85.6035,115.948 -87.7806,119.516 -86.3955,119.868 -86.6011,115.694 -87.5683,115.341 -89.1235,119.026 -86.6011,115.694 -89.1235,119.026 -87.7806,119.516 -87.5683,115.341 -88.4956,114.894 -90.4109,118.406 -87.5683,115.341 -90.4109,118.406 -89.1235,119.026 -88.4956,114.894 -89.3736,114.357 -91.6299,117.659 -88.4956,114.894 -91.6299,117.659 -90.4109,118.406 -89.3736,114.357 -90.1935,113.734 -92.7683,116.795 -89.3736,114.357 -92.7683,116.795 -91.6299,117.659 -90.1935,113.734 -90.9592,113.02 -93.8346,115.801 -90.1935,113.734 -93.8346,115.801 -92.7683,116.795 -90.9592,113.02 -91.6725,112.197 -94.8358,114.645 -90.9592,113.02 -94.8358,114.645 -93.8346,115.801 -91.6725,112.197 -92.291,111.3 -95.7039,113.386 -91.6725,112.197 -95.7039,113.386 -94.8358,114.645 -92.291,111.3 -92.8073,110.34 -96.4286,112.039 -92.291,111.3 -96.4286,112.039 -95.7039,113.386 -92.8073,110.34 -93.2152,109.33 -97.0011,110.621 -92.8073,110.34 -97.0011,110.621 -96.4286,112.039 -93.2152,109.33 -93.5097,108.281 -97.4144,109.148 -93.2152,109.33 -97.4144,109.148 -97.0011,110.621 -93.5097,108.281 -93.6872,107.206 -97.6636,107.639 -93.5097,108.281 -97.6636,107.639 -97.4144,109.148 -93.6872,107.206 -93.7456,106.118 -97.7456,106.112 -93.6872,107.206 -97.7456,106.112 -97.6636,107.639 -93.7456,106.118 -93.7448,105.502 -97.7448,105.496 -93.7456,106.118 -97.7448,105.496 -97.7456,106.112 -83.5021,120.151 -84.9821,120.081 -85.0118,120.379 -83.5021,120.151 -85.0118,120.379 -83.5019,120.451 -84.9821,120.081 -86.3955,119.868 -86.4549,120.162 -84.9821,120.081 -86.4549,120.162 -85.0118,120.379 -86.3955,119.868 -87.7806,119.516 -87.869,119.802 -86.3955,119.868 -87.869,119.802 -86.4549,120.162 -87.7806,119.516 -89.1235,119.026 -89.2401,119.303 -87.7806,119.516 -89.2401,119.303 -87.869,119.802 -89.1235,119.026 -90.4109,118.406 -90.5546,118.669 -89.1235,119.026 -90.5546,118.669 -89.2401,119.303 -90.4109,118.406 -91.6299,117.659 -91.7991,117.907 -90.4109,118.406 -91.7991,117.907 -90.5546,118.669 -91.6299,117.659 -92.7683,116.795 -92.9614,117.025 -91.6299,117.659 -92.9614,117.025 -91.7991,117.907 -92.7683,116.795 -93.8346,115.801 -94.0503,116.01 -92.7683,116.795 -94.0503,116.01 -92.9614,117.025 -93.8346,115.801 -94.8358,114.645 -95.073,114.828 -93.8346,115.801 -95.073,114.828 -94.0503,116.01 -94.8358,114.645 -95.7039,113.386 -95.9599,113.542 -94.8358,114.645 -95.9599,113.542 -95.073,114.828 -95.7039,113.386 -96.4286,112.039 -96.7002,112.166 -95.7039,113.386 -96.7002,112.166 -95.9599,113.542 -96.4286,112.039 -97.0011,110.621 -97.285,110.718 -96.4286,112.039 -97.285,110.718 -96.7002,112.166 -97.0011,110.621 -97.4144,109.148 -97.7073,109.213 -97.0011,110.621 -97.7073,109.213 -97.285,110.718 -97.4144,109.148 -97.6636,107.639 -97.9618,107.672 -97.4144,109.148 -97.9618,107.672 -97.7073,109.213 -97.6636,107.639 -97.7456,106.112 -98.0456,106.112 -97.6636,107.639 -98.0456,106.112 -97.9618,107.672 -97.7456,106.112 -97.7448,105.496 -98.0448,105.496 -97.7456,106.112 -98.0448,105.496 -98.0456,106.112 -83.5019,120.451 -85.0118,120.379 -85.4085,124.36 -83.5019,120.451 -85.4085,124.36 -83.4991,124.451 -85.0118,120.379 -86.4549,120.162 -87.2469,124.083 -85.0118,120.379 -87.2469,124.083 -85.4085,124.36 -86.4549,120.162 -87.869,119.802 -89.0485,123.624 -86.4549,120.162 -89.0485,123.624 -87.2469,124.083 -87.869,119.802 -89.2401,119.303 -90.7953,122.988 -87.869,119.802 -90.7953,122.988 -89.0485,123.624 -89.2401,119.303 -90.5546,118.669 -92.4699,122.181 -89.2401,119.303 -92.4699,122.181 -90.7953,122.988 -90.5546,118.669 -91.7991,117.907 -94.0555,121.21 -90.5546,118.669 -94.0555,121.21 -92.4699,122.181 -91.7991,117.907 -92.9614,117.025 -95.5362,120.086 -91.7991,117.907 -95.5362,120.086 -94.0555,121.21 -92.9614,117.025 -94.0503,116.01 -96.9257,118.79 -92.9614,117.025 -96.9257,118.79 -95.5362,120.086 -94.0503,116.01 -95.073,114.828 -98.2363,117.277 -94.0503,116.01 -98.2363,117.277 -96.9257,118.79 -95.073,114.828 -95.9599,113.542 -99.3728,115.628 -95.073,114.828 -99.3728,115.628 -98.2363,117.277 -95.9599,113.542 -96.7002,112.166 -100.322,113.865 -95.9599,113.542 -100.322,113.865 -99.3728,115.628 -96.7002,112.166 -97.285,110.718 -101.071,112.009 -96.7002,112.166 -101.071,112.009 -100.322,113.865 -97.285,110.718 -97.7073,109.213 -101.612,110.081 -97.285,110.718 -101.612,110.081 -101.071,112.009 -97.7073,109.213 -97.9618,107.672 -101.938,108.106 -97.7073,109.213 -101.938,108.106 -101.612,110.081 -97.9618,107.672 -98.0456,106.112 -102.046,106.106 -97.9618,107.672 -102.046,106.106 -101.938,108.106 -98.0456,106.112 -98.0448,105.496 -102.045,105.491 -98.0456,106.112 -102.045,105.491 -102.046,106.106 -25.1848,33.9627 -27.0929,29.9618 -27.0948,33.9618 -25.1848,33.9627 -25.1829,29.9627 -27.0929,29.9618 -27.0948,33.9618 -28.7629,29.961 -28.7648,33.961 -27.0948,33.9618 -27.0929,29.9618 -28.7629,29.961 -28.7648,33.961 -29.8128,29.9606 -29.8146,33.9606 -28.7648,33.961 -28.7629,29.961 -29.8128,29.9606 -29.8146,33.9606 -30.1389,29.931 -30.8569,33.866 -29.8146,33.9606 -29.8128,29.9606 -30.1389,29.931 -30.8569,33.866 -30.4546,29.8435 -31.8654,33.5864 -30.8569,33.866 -30.1389,29.931 -30.4546,29.8435 -31.8654,33.5864 -30.7494,29.7009 -32.8075,33.1308 -31.8654,33.5864 -30.4546,29.8435 -30.7494,29.7009 -32.8075,33.1308 -31.0139,29.5078 -33.6529,32.5138 -32.8075,33.1308 -30.7494,29.7009 -31.0139,29.5078 -33.6529,32.5138 -31.2397,29.2705 -34.3741,31.7555 -33.6529,32.5138 -31.0139,29.5078 -31.2397,29.2705 -34.3741,31.7555 -31.5441,28.8273 -34.976,30.8821 -34.3741,31.7555 -31.2397,29.2705 -31.5441,28.8273 -34.976,30.8821 -31.8003,28.3284 -35.4697,29.9209 -34.976,30.8821 -31.5441,28.8273 -31.8003,28.3284 -35.4697,29.9209 -31.9898,27.8003 -35.8346,28.9037 -35.4697,29.9209 -31.8003,28.3284 -31.9898,27.8003 -35.8346,28.9037 -32.1092,27.2522 -36.0646,27.8479 -35.8346,28.9037 -31.9898,27.8003 -32.1092,27.2522 -36.0646,27.8479 -32.1565,26.6933 -36.1557,26.7712 -36.0646,27.8479 -32.1092,27.2522 -32.1565,26.6933 -36.1557,26.7712 -32.1562,25.5354 -36.1562,25.5314 -36.1557,26.7712 -32.1565,26.6933 -32.1562,25.5354 -36.1562,25.5314 -32.1552,24.4854 -36.1552,24.4814 -36.1562,25.5314 -32.1562,25.5354 -32.1552,24.4854 -36.1552,24.4814 -32.1551,24.4154 -36.1551,24.4114 -36.1552,24.4814 -32.1552,24.4854 -32.1551,24.4154 -25.1848,33.9627 -27.0948,33.9618 -27.0948,33.9618 -25.1848,33.9627 -25.1848,33.9627 -27.0948,33.9618 -27.0948,33.9618 -28.7648,33.961 -28.7648,33.961 -27.0948,33.9618 -27.0948,33.9618 -28.7648,33.961 -28.7648,33.961 -29.8146,33.9606 -29.8146,33.9606 -28.7648,33.961 -28.7648,33.961 -29.8146,33.9606 -29.8146,33.9606 -30.8569,33.866 -30.8569,33.866 -29.8146,33.9606 -29.8146,33.9606 -30.8569,33.866 -30.8569,33.866 -31.8654,33.5864 -31.8654,33.5864 -30.8569,33.866 -30.8569,33.866 -31.8654,33.5864 -31.8654,33.5864 -32.8075,33.1308 -32.8075,33.1308 -31.8654,33.5864 -31.8654,33.5864 -32.8075,33.1308 -32.8075,33.1308 -33.6529,32.5138 -33.6529,32.5138 -32.8075,33.1308 -32.8075,33.1308 -33.6529,32.5138 -33.6529,32.5138 -34.3741,31.7555 -34.3741,31.7555 -33.6529,32.5138 -33.6529,32.5138 -34.3741,31.7555 -34.3741,31.7555 -34.976,30.8821 -34.976,30.8821 -34.3741,31.7555 -34.3741,31.7555 -34.976,30.8821 -34.976,30.8821 -35.4697,29.9209 -35.4697,29.9209 -34.976,30.8821 -34.976,30.8821 -35.4697,29.9209 -35.4697,29.9209 -35.8346,28.9037 -35.8346,28.9037 -35.4697,29.9209 -35.4697,29.9209 -35.8346,28.9037 -35.8346,28.9037 -36.0646,27.8479 -36.0646,27.8479 -35.8346,28.9037 -35.8346,28.9037 -36.0646,27.8479 -36.0646,27.8479 -36.1557,26.7712 -36.1557,26.7712 -36.0646,27.8479 -36.0646,27.8479 -36.1557,26.7712 -36.1557,26.7712 -36.1562,25.5314 -36.1562,25.5314 -36.1557,26.7712 -36.1557,26.7712 -36.1562,25.5314 -36.1562,25.5314 -36.1552,24.4814 -36.1552,24.4814 -36.1562,25.5314 -36.1562,25.5314 -36.1552,24.4814 -36.1552,24.4814 -36.1551,24.4114 -36.1551,24.4114 -36.1552,24.4814 -36.1552,24.4814 -36.1551,24.4114 -36.1551,24.4114 -40.1562,25.5273 -36.1562,25.5314 -36.1551,24.4114 -40.1551,24.4073 -40.1562,25.5273 -36.1562,25.5314 -40.1574,26.6533 -36.1574,26.6573 -36.1562,25.5314 -40.1562,25.5273 -40.1574,26.6533 -36.1574,26.6573 -40.056,28.2357 -36.0892,27.7212 -36.1574,26.6573 -40.1574,26.6533 -40.056,28.2357 -36.0892,27.7212 -39.7503,29.7916 -35.8837,28.7672 -36.0892,27.7212 -40.056,28.2357 -39.7503,29.7916 -35.8837,28.7672 -39.2455,31.2948 -35.5443,29.7778 -35.8837,28.7672 -39.7503,29.7916 -39.2455,31.2948 -35.5443,29.7778 -38.5501,32.7198 -35.0768,30.7358 -35.5443,29.7778 -39.2455,31.2948 -38.5501,32.7198 -35.0768,30.7358 -37.6759,34.0427 -34.4891,31.6251 -35.0768,30.7358 -38.5501,32.7198 -37.6759,34.0427 -34.4891,31.6251 -36.5669,35.2816 -33.8222,32.3718 -34.4891,31.6251 -37.6759,34.0427 -36.5669,35.2816 -33.8222,32.3718 -35.1779,36.3735 -32.9985,33.0194 -33.8222,32.3718 -36.5669,35.2816 -35.1779,36.3735 -32.9985,33.0194 -33.6158,37.1991 -32.0721,33.509 -32.9985,33.0194 -35.1779,36.3735 -33.6158,37.1991 -32.0721,33.509 -31.9312,37.7317 -31.073,33.8248 -32.0721,33.509 -33.6158,37.1991 -31.9312,37.7317 -31.073,33.8248 -30.1784,37.9541 -30.0336,33.9567 -31.073,33.8248 -31.9312,37.7317 -30.1784,37.9541 -30.0336,33.9567 -28.8366,37.961 -28.8348,33.961 -30.0336,33.9567 -30.1784,37.9541 -28.8366,37.961 -28.8348,33.961 -27.0966,37.9618 -27.0948,33.9618 -28.8348,33.961 -28.8366,37.961 -27.0966,37.9618 -27.0948,33.9618 -25.1866,37.9627 -25.1848,33.9627 -27.0948,33.9618 -27.0966,37.9618 -25.1866,37.9627 -36.1551,24.4114 -36.1562,25.5314 -36.1562,25.5314 -36.1551,24.4114 -36.1551,24.4114 -36.1562,25.5314 -36.1562,25.5314 -36.1574,26.6573 -36.1574,26.6573 -36.1562,25.5314 -36.1562,25.5314 -36.1574,26.6573 -36.1574,26.6573 -36.0892,27.7212 -36.0892,27.7212 -36.1574,26.6573 -36.1574,26.6573 -36.0892,27.7212 -36.0892,27.7212 -35.8837,28.7672 -35.8837,28.7672 -36.0892,27.7212 -36.0892,27.7212 -35.8837,28.7672 -35.8837,28.7672 -35.5443,29.7778 -35.5443,29.7778 -35.8837,28.7672 -35.8837,28.7672 -35.5443,29.7778 -35.5443,29.7778 -35.0768,30.7358 -35.0768,30.7358 -35.5443,29.7778 -35.5443,29.7778 -35.0768,30.7358 -35.0768,30.7358 -34.4891,31.6251 -34.4891,31.6251 -35.0768,30.7358 -35.0768,30.7358 -34.4891,31.6251 -34.4891,31.6251 -33.8222,32.3718 -33.8222,32.3718 -34.4891,31.6251 -34.4891,31.6251 -33.8222,32.3718 -33.8222,32.3718 -32.9985,33.0194 -32.9985,33.0194 -33.8222,32.3718 -33.8222,32.3718 -32.9985,33.0194 -32.9985,33.0194 -32.0721,33.509 -32.0721,33.509 -32.9985,33.0194 -32.9985,33.0194 -32.0721,33.509 -32.0721,33.509 -31.073,33.8248 -31.073,33.8248 -32.0721,33.509 -32.0721,33.509 -31.073,33.8248 -31.073,33.8248 -30.0336,33.9567 -30.0336,33.9567 -31.073,33.8248 -31.073,33.8248 -30.0336,33.9567 -30.0336,33.9567 -28.8348,33.961 -28.8348,33.961 -30.0336,33.9567 -30.0336,33.9567 -28.8348,33.961 -28.8348,33.961 -27.0948,33.9618 -27.0948,33.9618 -28.8348,33.961 -28.8348,33.961 -27.0948,33.9618 -27.0948,33.9618 -25.1848,33.9627 -25.1848,33.9627 -27.0948,33.9618 -27.0948,33.9618 -25.1848,33.9627 -93.7042,-24.7786 -93.704,-23.7786 -93.704,-23.7786 -93.7042,-24.7786 -93.7042,-24.7786 -93.704,-23.7786 -93.704,-23.7786 -93.7021,-15.4286 -93.7021,-15.4286 -93.704,-23.7786 -93.704,-23.7786 -93.7021,-15.4286 -93.7021,-15.4286 -93.7007,-9.05861 -93.7007,-9.05861 -93.7021,-15.4286 -93.7021,-15.4286 -93.7007,-9.05861 -93.7007,-9.05861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7007,-9.05861 -93.7007,-9.05861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7002,-6.77861 -93.7002,-6.77861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7002,-6.77861 -93.7042,-24.7786 -93.704,-23.7786 -89.704,-23.7795 -93.7042,-24.7786 -89.704,-23.7795 -89.7042,-24.7795 -93.704,-23.7786 -93.7021,-15.4286 -89.7021,-15.4295 -93.704,-23.7786 -89.7021,-15.4295 -89.704,-23.7795 -93.7021,-15.4286 -93.7007,-9.05861 -89.7007,-9.05951 -93.7021,-15.4286 -89.7007,-9.05951 -89.7021,-15.4295 -93.7007,-9.05861 -93.7004,-7.92861 -89.7004,-7.92951 -93.7007,-9.05861 -89.7004,-7.92951 -89.7007,-9.05951 -93.7004,-7.92861 -93.7002,-6.77861 -89.7002,-6.77951 -93.7004,-7.92861 -89.7002,-6.77951 -89.7004,-7.92951 -36.1551,24.4114 -36.1562,25.5316 -36.1562,25.5316 -36.1551,24.4114 -36.1551,24.4114 -36.1562,25.5316 -36.1562,25.5316 -36.1575,26.7416 -36.1575,26.7416 -36.1562,25.5316 -36.1562,25.5316 -36.1575,26.7416 -36.1575,26.7416 -36.2262,27.7806 -36.2262,27.7806 -36.1575,26.7416 -36.1575,26.7416 -36.2262,27.7806 -36.2262,27.7806 -36.429,28.802 -36.429,28.802 -36.2262,27.7806 -36.2262,27.7806 -36.429,28.802 -36.429,28.802 -36.7624,29.7884 -36.7624,29.7884 -36.429,28.802 -36.429,28.802 -36.7624,29.7884 -36.7624,29.7884 -37.221,30.7233 -37.221,30.7233 -36.7624,29.7884 -36.7624,29.7884 -37.221,30.7233 -37.221,30.7233 -37.7969,31.5908 -37.7969,31.5908 -37.221,30.7233 -37.221,30.7233 -37.7969,31.5908 -37.7969,31.5908 -38.4884,32.3627 -38.4884,32.3627 -37.7969,31.5908 -37.7969,31.5908 -38.4884,32.3627 -38.4884,32.3627 -39.2729,32.9819 -39.2729,32.9819 -38.4884,32.3627 -38.4884,32.3627 -39.2729,32.9819 -39.2729,32.9819 -40.1509,33.4595 -40.1509,33.4595 -39.2729,32.9819 -39.2729,32.9819 -40.1509,33.4595 -40.1509,33.4595 -41.0971,33.7816 -41.0971,33.7816 -40.1509,33.4595 -40.1509,33.4595 -41.0971,33.7816 -41.0971,33.7816 -42.0841,33.939 -42.0841,33.939 -41.0971,33.7816 -41.0971,33.7816 -42.0841,33.939 -42.0841,33.939 -43.0848,33.9545 -43.0848,33.9545 -42.0841,33.939 -42.0841,33.939 -43.0848,33.9545 -43.0848,33.9545 -45.0948,33.9536 -45.0948,33.9536 -43.0848,33.9545 -43.0848,33.9545 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 -47.1048,33.9526 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 -36.1551,24.4114 -36.1562,25.5316 -32.1562,25.5357 -36.1551,24.4114 -32.1562,25.5357 -32.1551,24.4154 -36.1562,25.5316 -36.1575,26.7416 -32.1575,26.7456 -36.1562,25.5316 -32.1575,26.7456 -32.1562,25.5357 -36.1575,26.7416 -36.2262,27.7806 -32.2604,28.3032 -36.1575,26.7416 -32.2604,28.3032 -32.1575,26.7456 -36.2262,27.7806 -36.429,28.802 -32.5644,29.8342 -36.2262,27.7806 -32.5644,29.8342 -32.2604,28.3032 -36.429,28.802 -36.7624,29.7884 -33.0644,31.3129 -36.429,28.802 -33.0644,31.3129 -32.5644,29.8342 -36.7624,29.7884 -37.221,30.7233 -33.7517,32.7143 -36.7624,29.7884 -33.7517,32.7143 -33.0644,31.3129 -37.221,30.7233 -37.7969,31.5908 -34.615,34.0148 -37.221,30.7233 -34.615,34.0148 -33.7517,32.7143 -37.7969,31.5908 -38.4884,32.3627 -35.7526,35.2809 -37.7969,31.5908 -35.7526,35.2809 -34.615,34.0148 -38.4884,32.3627 -39.2729,32.9819 -37.0703,36.3209 -38.4884,32.3627 -37.0703,36.3209 -35.7526,35.2809 -39.2729,32.9819 -40.1509,33.4595 -38.545,37.1229 -39.2729,32.9819 -38.545,37.1229 -37.0703,36.3209 -40.1509,33.4595 -41.0971,33.7816 -40.1341,37.6639 -40.1509,33.4595 -40.1341,37.6639 -38.545,37.1229 -41.0971,33.7816 -42.0841,33.939 -41.7918,37.9283 -41.0971,33.7816 -41.7918,37.9283 -40.1341,37.6639 -42.0841,33.939 -43.0848,33.9545 -43.0866,37.9545 -42.0841,33.939 -43.0866,37.9545 -41.7918,37.9283 -43.0848,33.9545 -45.0948,33.9536 -45.0966,37.9536 -43.0848,33.9545 -45.0966,37.9536 -43.0866,37.9545 -45.0948,33.9536 -47.1048,33.9526 -47.1066,37.9526 -45.0948,33.9536 -47.1066,37.9526 -45.0966,37.9536 -98.0042,-24.7776 -102.004,-23.7767 -98.004,-23.7776 -98.0042,-24.7776 -102.004,-24.7767 -102.004,-23.7767 -98.004,-23.7776 -102.002,-15.4267 -98.0021,-15.4276 -98.004,-23.7776 -102.004,-23.7767 -102.002,-15.4267 -98.0021,-15.4276 -102.001,-9.05673 -98.0007,-9.05764 -98.0021,-15.4276 -102.002,-15.4267 -102.001,-9.05673 -98.0007,-9.05764 -102,-7.92673 -98.0004,-7.92764 -98.0007,-9.05764 -102.001,-9.05673 -102,-7.92673 -98.0004,-7.92764 -102,-6.77673 -98.0002,-6.77764 -98.0004,-7.92764 -102,-7.92673 -102,-6.77673 -97.7042,-24.7777 -98.004,-23.7776 -97.704,-23.7777 -97.7042,-24.7777 -98.0042,-24.7776 -98.004,-23.7776 -97.704,-23.7777 -98.0021,-15.4276 -97.7021,-15.4277 -97.704,-23.7777 -98.004,-23.7776 -98.0021,-15.4276 -97.7021,-15.4277 -98.0007,-9.05764 -97.7007,-9.05771 -97.7021,-15.4277 -98.0021,-15.4276 -98.0007,-9.05764 -97.7007,-9.05771 -98.0004,-7.92764 -97.7004,-7.92771 -97.7007,-9.05771 -98.0007,-9.05764 -98.0004,-7.92764 -97.7004,-7.92771 -98.0002,-6.77764 -97.7002,-6.77771 -97.7004,-7.92771 -98.0004,-7.92764 -98.0002,-6.77764 -93.7042,-24.7786 -97.704,-23.7777 -93.704,-23.7786 -93.7042,-24.7786 -97.7042,-24.7777 -97.704,-23.7777 -93.704,-23.7786 -97.7021,-15.4277 -93.7021,-15.4286 -93.704,-23.7786 -97.704,-23.7777 -97.7021,-15.4277 -93.7021,-15.4286 -97.7007,-9.05771 -93.7007,-9.05861 -93.7021,-15.4286 -97.7021,-15.4277 -97.7007,-9.05771 -93.7007,-9.05861 -97.7004,-7.92771 -93.7004,-7.92861 -93.7007,-9.05861 -97.7007,-9.05771 -97.7004,-7.92771 -93.7004,-7.92861 -97.7002,-6.77771 -93.7002,-6.77861 -93.7004,-7.92861 -97.7004,-7.92771 -97.7002,-6.77771 -93.7042,-24.7786 -93.704,-23.7786 -93.704,-23.7786 -93.7042,-24.7786 -93.7042,-24.7786 -93.704,-23.7786 -93.704,-23.7786 -93.7021,-15.4286 -93.7021,-15.4286 -93.704,-23.7786 -93.704,-23.7786 -93.7021,-15.4286 -93.7021,-15.4286 -93.7007,-9.05861 -93.7007,-9.05861 -93.7021,-15.4286 -93.7021,-15.4286 -93.7007,-9.05861 -93.7007,-9.05861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7007,-9.05861 -93.7007,-9.05861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7002,-6.77861 -93.7002,-6.77861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7002,-6.77861 -36.1551,24.4114 -40.1562,25.5273 -36.1562,25.5314 -36.1551,24.4114 -40.1551,24.4073 -40.1562,25.5273 -36.1562,25.5314 -40.1575,26.5621 -36.1577,26.6062 -36.1562,25.5314 -40.1562,25.5273 -40.1575,26.5621 -36.1577,26.6062 -40.1959,27.0665 -36.2356,27.6287 -36.1577,26.6062 -40.1575,26.5621 -40.1959,27.0665 -36.2356,27.6287 -40.2994,27.5617 -36.4454,28.6325 -36.2356,27.6287 -40.1959,27.0665 -40.2994,27.5617 -36.4454,28.6325 -40.4662,28.0393 -36.7835,29.6007 -36.4454,28.6325 -40.2994,27.5617 -40.4662,28.0393 -36.7835,29.6007 -40.6935,28.4912 -37.2443,30.5168 -36.7835,29.6007 -40.4662,28.0393 -40.6935,28.4912 -37.2443,30.5168 -40.9774,28.9098 -37.8199,31.3655 -37.2443,30.5168 -40.6935,28.4912 -40.9774,28.9098 -37.8199,31.3655 -41.4071,29.4087 -38.4807,32.1357 -37.8199,31.3655 -40.9774,28.9098 -41.4071,29.4087 -38.4807,32.1357 -41.6367,29.6145 -39.2458,32.8213 -38.4807,32.1357 -41.4071,29.4087 -41.6367,29.6145 -39.2458,32.8213 -41.8995,29.7758 -40.1214,33.3589 -39.2458,32.8213 -41.6367,29.6145 -41.8995,29.7758 -40.1214,33.3589 -42.187,29.8876 -41.079,33.731 -40.1214,33.3589 -41.8995,29.7758 -42.187,29.8876 -41.079,33.731 -42.4898,29.946 -42.0878,33.9257 -41.079,33.731 -42.187,29.8876 -42.4898,29.946 -42.0878,33.9257 -45.0929,29.9536 -45.0948,33.9536 -42.0878,33.9257 -42.4898,29.946 -45.0929,29.9536 -45.0948,33.9536 -47.1029,29.9526 -47.1048,33.9526 -45.0948,33.9536 -45.0929,29.9536 -47.1029,29.9526 -36.1551,24.4114 -36.1562,25.5314 -36.1562,25.5314 -36.1551,24.4114 -36.1551,24.4114 -36.1562,25.5314 -36.1562,25.5314 -36.1577,26.6062 -36.1577,26.6062 -36.1562,25.5314 -36.1562,25.5314 -36.1577,26.6062 -36.1577,26.6062 -36.2356,27.6287 -36.2356,27.6287 -36.1577,26.6062 -36.1577,26.6062 -36.2356,27.6287 -36.2356,27.6287 -36.4454,28.6325 -36.4454,28.6325 -36.2356,27.6287 -36.2356,27.6287 -36.4454,28.6325 -36.4454,28.6325 -36.7835,29.6007 -36.7835,29.6007 -36.4454,28.6325 -36.4454,28.6325 -36.7835,29.6007 -36.7835,29.6007 -37.2443,30.5168 -37.2443,30.5168 -36.7835,29.6007 -36.7835,29.6007 -37.2443,30.5168 -37.2443,30.5168 -37.8199,31.3655 -37.8199,31.3655 -37.2443,30.5168 -37.2443,30.5168 -37.8199,31.3655 -37.8199,31.3655 -38.4807,32.1357 -38.4807,32.1357 -37.8199,31.3655 -37.8199,31.3655 -38.4807,32.1357 -38.4807,32.1357 -39.2458,32.8213 -39.2458,32.8213 -38.4807,32.1357 -38.4807,32.1357 -39.2458,32.8213 -39.2458,32.8213 -40.1214,33.3589 -40.1214,33.3589 -39.2458,32.8213 -39.2458,32.8213 -40.1214,33.3589 -40.1214,33.3589 -41.079,33.731 -41.079,33.731 -40.1214,33.3589 -40.1214,33.3589 -41.079,33.731 -41.079,33.731 -42.0878,33.9257 -42.0878,33.9257 -41.079,33.731 -41.079,33.731 -42.0878,33.9257 -42.0878,33.9257 -45.0948,33.9536 -45.0948,33.9536 -42.0878,33.9257 -42.0878,33.9257 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 -47.1048,33.9526 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 -44.4551,24.403 -44.4726,24.6639 -44.4726,24.6639 -44.4551,24.403 -44.4551,24.403 -44.4726,24.6639 -44.4726,24.6639 -44.5277,24.8586 -44.5277,24.8586 -44.4726,24.6639 -44.4726,24.6639 -44.5277,24.8586 -44.5277,24.8586 -44.6187,25.0394 -44.6187,25.0394 -44.5277,24.8586 -44.5277,24.8586 -44.6187,25.0394 -44.6187,25.0394 -44.9393,25.4349 -44.9393,25.4349 -44.6187,25.0394 -44.6187,25.0394 -44.9393,25.4349 -44.9393,25.4349 -45.1372,25.6704 -45.1372,25.6704 -44.9393,25.4349 -44.9393,25.4349 -45.1372,25.6704 -45.1372,25.6704 -45.1228,25.661 -45.1228,25.661 -45.1372,25.6704 -45.1372,25.6704 -45.1228,25.661 -45.1228,25.661 -45.1066,25.6553 -45.1066,25.6553 -45.1228,25.661 -45.1228,25.661 -45.1066,25.6553 -45.1066,25.6553 -47.101,25.6526 -47.101,25.6526 -45.1066,25.6553 -45.1066,25.6553 -47.101,25.6526 -44.4551,24.403 -44.4726,24.6639 -40.5379,25.384 -44.4551,24.403 -40.5379,25.384 -40.4551,24.407 -44.4726,24.6639 -44.5277,24.8586 -40.7999,26.3089 -44.4726,24.6639 -40.7999,26.3089 -40.5379,25.384 -44.5277,24.8586 -44.6187,25.0394 -41.2318,27.1676 -44.5277,24.8586 -41.2318,27.1676 -40.7999,26.3089 -44.6187,25.0394 -44.9393,25.4349 -41.8855,28.0183 -44.6187,25.0394 -41.8855,28.0183 -41.2318,27.1676 -44.9393,25.4349 -45.1372,25.6704 -42.5645,28.7332 -44.9393,25.4349 -42.5645,28.7332 -41.8855,28.0183 -45.1372,25.6704 -45.1228,25.661 -43.3519,29.2476 -45.1372,25.6704 -43.3519,29.2476 -42.5645,28.7332 -45.1228,25.661 -45.1066,25.6553 -44.239,29.56 -45.1228,25.661 -44.239,29.56 -43.3519,29.2476 -45.1066,25.6553 -47.101,25.6526 -47.1028,29.6526 -45.1066,25.6553 -47.1028,29.6526 -44.239,29.56 -40.4551,24.407 -40.5379,25.384 -40.2428,25.438 -40.4551,24.407 -40.2428,25.438 -40.1551,24.4073 -40.5379,25.384 -40.7999,26.3089 -40.5203,26.4176 -40.5379,25.384 -40.5203,26.4176 -40.2428,25.438 -40.7999,26.3089 -41.2318,27.1676 -40.9778,27.3272 -40.7999,26.3089 -40.9778,27.3272 -40.5203,26.4176 -41.2318,27.1676 -41.8855,28.0183 -41.6565,28.2121 -41.2318,27.1676 -41.6565,28.2121 -40.9778,27.3272 -41.8855,28.0183 -42.5645,28.7332 -42.3715,28.963 -41.8855,28.0183 -42.3715,28.963 -41.6565,28.2121 -42.5645,28.7332 -43.3519,29.2476 -43.2191,29.5166 -42.5645,28.7332 -43.2191,29.5166 -42.3715,28.963 -43.3519,29.2476 -44.239,29.56 -44.1739,29.8529 -43.3519,29.2476 -44.1739,29.8529 -43.2191,29.5166 -44.239,29.56 -47.1028,29.6526 -47.1029,29.9526 -44.239,29.56 -47.1029,29.9526 -44.1739,29.8529 -25.1848,33.9627 -27.0948,33.9618 -27.0948,33.9618 -25.1848,33.9627 -25.1848,33.9627 -27.0948,33.9618 -27.0948,33.9618 -28.7648,33.961 -28.7648,33.961 -27.0948,33.9618 -27.0948,33.9618 -28.7648,33.961 -28.7648,33.961 -36.1448,33.9577 -36.1448,33.9577 -28.7648,33.961 -28.7648,33.961 -36.1448,33.9577 -36.1448,33.9577 -42.6648,33.9547 -42.6648,33.9547 -36.1448,33.9577 -36.1448,33.9577 -42.6648,33.9547 -42.6648,33.9547 -45.0948,33.9536 -45.0948,33.9536 -42.6648,33.9547 -42.6648,33.9547 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 -47.1048,33.9526 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 -25.1848,33.9627 -27.0948,33.9618 -27.0966,37.9618 -25.1848,33.9627 -27.0966,37.9618 -25.1866,37.9627 -27.0948,33.9618 -28.7648,33.961 -28.7666,37.961 -27.0948,33.9618 -28.7666,37.961 -27.0966,37.9618 -28.7648,33.961 -36.1448,33.9577 -36.1466,37.9577 -28.7648,33.961 -36.1466,37.9577 -28.7666,37.961 -36.1448,33.9577 -42.6648,33.9547 -42.6666,37.9547 -36.1448,33.9577 -42.6666,37.9547 -36.1466,37.9577 -42.6648,33.9547 -45.0948,33.9536 -45.0966,37.9536 -42.6648,33.9547 -45.0966,37.9536 -42.6666,37.9547 -45.0948,33.9536 -47.1048,33.9526 -47.1066,37.9526 -45.0948,33.9536 -47.1066,37.9526 -45.0966,37.9536 -25.1866,37.9627 -27.0966,37.9618 -27.0967,38.2618 -25.1866,37.9627 -27.0967,38.2618 -25.1867,38.2627 -27.0966,37.9618 -28.7666,37.961 -28.7667,38.261 -27.0966,37.9618 -28.7667,38.261 -27.0967,38.2618 -28.7666,37.961 -36.1466,37.9577 -36.1467,38.2577 -28.7666,37.961 -36.1467,38.2577 -28.7667,38.261 -36.1466,37.9577 -42.6666,37.9547 -42.6667,38.2547 -36.1466,37.9577 -42.6667,38.2547 -36.1467,38.2577 -42.6666,37.9547 -45.0966,37.9536 -45.0967,38.2536 -42.6666,37.9547 -45.0967,38.2536 -42.6667,38.2547 -45.0966,37.9536 -47.1066,37.9526 -47.1067,38.2526 -45.0966,37.9536 -47.1067,38.2526 -45.0967,38.2536 -25.1867,38.2627 -27.0967,38.2618 -27.0986,42.2618 -25.1867,38.2627 -27.0986,42.2618 -25.1886,42.2627 -27.0967,38.2618 -28.7667,38.261 -28.7686,42.261 -27.0967,38.2618 -28.7686,42.261 -27.0986,42.2618 -28.7667,38.261 -36.1467,38.2577 -36.1486,42.2577 -28.7667,38.261 -36.1486,42.2577 -28.7686,42.261 -36.1467,38.2577 -42.6667,38.2547 -42.6686,42.2547 -36.1467,38.2577 -42.6686,42.2547 -36.1486,42.2577 -42.6667,38.2547 -45.0967,38.2536 -45.0986,42.2536 -42.6667,38.2547 -45.0986,42.2536 -42.6686,42.2547 -45.0967,38.2536 -47.1067,38.2526 -47.1086,42.2526 -45.0967,38.2536 -47.1086,42.2526 -45.0986,42.2536 -25.1848,33.9627 -27.0929,29.9618 -27.0948,33.9618 -25.1848,33.9627 -25.1829,29.9627 -27.0929,29.9618 -27.0948,33.9618 -28.7629,29.961 -28.7648,33.961 -27.0948,33.9618 -27.0929,29.9618 -28.7629,29.961 -28.7648,33.961 -36.1429,29.9577 -36.1448,33.9577 -28.7648,33.961 -28.7629,29.961 -36.1429,29.9577 -36.1448,33.9577 -42.6629,29.9547 -42.6648,33.9547 -36.1448,33.9577 -36.1429,29.9577 -42.6629,29.9547 -42.6648,33.9547 -45.0929,29.9536 -45.0948,33.9536 -42.6648,33.9547 -42.6629,29.9547 -45.0929,29.9536 -45.0948,33.9536 -47.1029,29.9526 -47.1048,33.9526 -45.0948,33.9536 -45.0929,29.9536 -47.1029,29.9526 -25.1848,33.9627 -27.0948,33.9618 -27.0948,33.9618 -25.1848,33.9627 -25.1848,33.9627 -27.0948,33.9618 -27.0948,33.9618 -28.7648,33.961 -28.7648,33.961 -27.0948,33.9618 -27.0948,33.9618 -28.7648,33.961 -28.7648,33.961 -36.1448,33.9577 -36.1448,33.9577 -28.7648,33.961 -28.7648,33.961 -36.1448,33.9577 -36.1448,33.9577 -42.6648,33.9547 -42.6648,33.9547 -36.1448,33.9577 -36.1448,33.9577 -42.6648,33.9547 -42.6648,33.9547 -45.0948,33.9536 -45.0948,33.9536 -42.6648,33.9547 -42.6648,33.9547 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 -47.1048,33.9526 -45.0948,33.9536 -45.0948,33.9536 -47.1048,33.9526 --45.3324,-72.66 --45.5031,-72.6471 --45.5031,-72.6471 --45.3324,-72.66 --45.3324,-72.66 --45.5031,-72.6471 --45.5031,-72.6471 --45.6315,-72.6067 --45.6315,-72.6067 --45.5031,-72.6471 --45.5031,-72.6471 --45.6315,-72.6067 --45.6315,-72.6067 --45.7486,-72.5403 --45.7486,-72.5403 --45.6315,-72.6067 --45.6315,-72.6067 --45.7486,-72.5403 --45.7486,-72.5403 --45.8149,-72.4856 --45.8149,-72.4856 --45.7486,-72.5403 --45.7486,-72.5403 --45.8149,-72.4856 --45.8149,-72.4856 --45.8257,-72.4705 --45.8257,-72.4705 --45.8149,-72.4856 --45.8149,-72.4856 --45.8257,-72.4705 --45.8257,-72.4705 --45.8329,-72.4533 --45.8329,-72.4533 --45.8257,-72.4705 --45.8257,-72.4705 --45.8329,-72.4533 --45.8329,-72.4533 --45.8359,-72.4349 --45.8359,-72.4349 --45.8329,-72.4533 --45.8329,-72.4533 --45.8359,-72.4349 --45.8359,-72.4349 --45.836,-72.3881 --45.836,-72.3881 --45.8359,-72.4349 --45.8359,-72.4349 --45.836,-72.3881 --45.3324,-72.66 --45.5031,-72.6471 --46.2991,-76.5671 --45.3324,-72.66 --46.2991,-76.5671 --45.3338,-76.66 --45.5031,-72.6471 --45.6315,-72.6067 --47.2272,-76.2746 --45.5031,-72.6471 --47.2272,-76.2746 --46.2991,-76.5671 --45.6315,-72.6067 --45.7486,-72.5403 --48.0739,-75.795 --45.6315,-72.6067 --48.0739,-75.795 --47.2272,-76.2746 --45.7486,-72.5403 --45.8149,-72.4856 --48.7746,-75.1763 --45.7486,-72.5403 --48.7746,-75.1763 --48.0739,-75.795 --45.8149,-72.4856 --45.8257,-72.4705 --49.3209,-74.4156 --45.8149,-72.4856 --49.3209,-74.4156 --48.7746,-75.1763 --45.8257,-72.4705 --45.8329,-72.4533 --49.6795,-73.5504 --45.8257,-72.4705 --49.6795,-73.5504 --49.3209,-74.4156 --45.8329,-72.4533 --45.8359,-72.4349 --49.8313,-72.6262 --45.8329,-72.4533 --49.8313,-72.6262 --49.6795,-73.5504 --45.8359,-72.4349 --45.836,-72.3881 --49.836,-72.3884 --45.8359,-72.4349 --49.836,-72.3884 --49.8313,-72.6262 --45.3338,-76.66 --46.2991,-76.5671 --46.3588,-76.8611 --45.3338,-76.66 --46.3588,-76.8611 --45.3339,-76.96 --46.2991,-76.5671 --47.2272,-76.2746 --47.3469,-76.5497 --46.2991,-76.5671 --47.3469,-76.5497 --46.3588,-76.8611 --47.2272,-76.2746 --48.0739,-75.795 --48.2483,-76.0392 --47.2272,-76.2746 --48.2483,-76.0392 --47.3469,-76.5497 --48.0739,-75.795 --48.7746,-75.1763 --48.9966,-75.3781 --48.0739,-75.795 --48.9966,-75.3781 --48.2483,-76.0392 --48.7746,-75.1763 --49.3209,-74.4156 --49.5831,-74.5615 --48.7746,-75.1763 --49.5831,-74.5615 --48.9966,-75.3781 --49.3209,-74.4156 --49.6795,-73.5504 --49.968,-73.6326 --49.3209,-74.4156 --49.968,-73.6326 --49.5831,-74.5615 --49.6795,-73.5504 --49.8313,-72.6262 --50.1309,-72.6405 --49.6795,-73.5504 --50.1309,-72.6405 --49.968,-73.6326 --49.8313,-72.6262 --49.836,-72.3884 --50.136,-72.3885 --49.8313,-72.6262 --50.136,-72.3885 --50.1309,-72.6405 --45.3352,-80.96 --46.3952,-80.9596 --46.3952,-80.9596 --45.3352,-80.96 --45.3352,-80.96 --46.3952,-80.9596 --46.3952,-80.9596 --49.2861,-80.9586 --49.2861,-80.9586 --46.3952,-80.9596 --46.3952,-80.9596 --49.2861,-80.9586 --49.2861,-80.9586 --50.3111,-80.8399 --50.3111,-80.8399 --49.2861,-80.9586 --49.2861,-80.9586 --50.3111,-80.8399 --50.3111,-80.8399 --51.2821,-80.4906 --51.2821,-80.4906 --50.3111,-80.8399 --50.3111,-80.8399 --51.2821,-80.4906 --51.2821,-80.4906 --52.1478,-79.9291 --52.1478,-79.9291 --51.2821,-80.4906 --51.2821,-80.4906 --52.1478,-79.9291 --52.1478,-79.9291 --52.8619,-79.187 --52.8619,-79.187 --52.1478,-79.9291 --52.1478,-79.9291 --52.8619,-79.187 --52.8619,-79.187 --53.4235,-78.3167 --53.4235,-78.3167 --52.8619,-79.187 --52.8619,-79.187 --53.4235,-78.3167 --53.4235,-78.3167 --53.8297,-77.3639 --53.8297,-77.3639 --53.4235,-78.3167 --53.4235,-78.3167 --53.8297,-77.3639 --53.8297,-77.3639 --54.069,-76.3561 --54.069,-76.3561 --53.8297,-77.3639 --53.8297,-77.3639 --54.069,-76.3561 --54.069,-76.3561 --54.1358,-74.2086 --54.1358,-74.2086 --54.069,-76.3561 --54.069,-76.3561 --54.1358,-74.2086 --54.1358,-74.2086 --54.136,-72.3886 --54.136,-72.3886 --54.1358,-74.2086 --54.1358,-74.2086 --54.136,-72.3886 --45.3352,-80.96 --46.3952,-80.9596 --46.3966,-84.9596 --45.3352,-80.96 --46.3966,-84.9596 --45.3366,-84.96 --46.3952,-80.9596 --49.2861,-80.9586 --49.2875,-84.9586 --46.3952,-80.9596 --49.2875,-84.9586 --46.3966,-84.9596 --49.2861,-80.9586 --50.3111,-80.8399 --51.2244,-84.7342 --49.2861,-80.9586 --51.2244,-84.7342 --49.2875,-84.9586 --50.3111,-80.8399 --51.2821,-80.4906 --53.0591,-84.0742 --50.3111,-80.8399 --53.0591,-84.0742 --51.2244,-84.7342 --51.2821,-80.4906 --52.1478,-79.9291 --54.695,-83.0133 --51.2821,-80.4906 --54.695,-83.0133 --53.0591,-84.0742 --52.1478,-79.9291 --52.8619,-79.187 --56.0266,-81.6333 --52.1478,-79.9291 --56.0266,-81.6333 --54.695,-83.0133 --52.8619,-79.187 --53.4235,-78.3167 --56.9565,-80.1923 --52.8619,-79.187 --56.9565,-80.1923 --56.0266,-81.6333 --53.4235,-78.3167 --53.8297,-77.3639 --57.6291,-78.6147 --53.4235,-78.3167 --57.6291,-78.6147 --56.9565,-80.1923 --53.8297,-77.3639 --54.069,-76.3561 --58.0252,-76.9461 --53.8297,-77.3639 --58.0252,-76.9461 --57.6291,-78.6147 --54.069,-76.3561 --54.1358,-74.2086 --58.1358,-74.209 --54.069,-76.3561 --58.1358,-74.209 --58.0252,-76.9461 --54.1358,-74.2086 --54.136,-72.3886 --58.136,-72.389 --54.1358,-74.2086 --58.136,-72.389 --58.1358,-74.209 --54.136,-72.3886 --54.1359,-73.6389 --54.1359,-73.6389 --54.136,-72.3886 --54.136,-72.3886 --54.1359,-73.6389 --54.1359,-73.6389 --54.1345,-74.6681 --54.1345,-74.6681 --54.1359,-73.6389 --54.1359,-73.6389 --54.1345,-74.6681 --54.1345,-74.6681 --54.0338,-75.6707 --54.0338,-75.6707 --54.1345,-74.6681 --54.1345,-74.6681 --54.0338,-75.6707 --54.0338,-75.6707 --53.7747,-76.6444 --53.7747,-76.6444 --54.0338,-75.6707 --54.0338,-75.6707 --53.7747,-76.6444 --53.7747,-76.6444 --53.3637,-77.5645 --53.3637,-77.5645 --53.7747,-76.6444 --53.7747,-76.6444 --53.3637,-77.5645 --53.3637,-77.5645 --52.8115,-78.4073 --52.8115,-78.4073 --53.3637,-77.5645 --53.3637,-77.5645 --52.8115,-78.4073 --52.8115,-78.4073 --52.0919,-79.1885 --52.0919,-79.1885 --52.8115,-78.4073 --52.8115,-78.4073 --52.0919,-79.1885 --52.0919,-79.1885 --51.3024,-79.8119 --51.3024,-79.8119 --52.0919,-79.1885 --52.0919,-79.1885 --51.3024,-79.8119 --51.3024,-79.8119 --50.4285,-80.3103 --50.4285,-80.3103 --51.3024,-79.8119 --51.3024,-79.8119 --50.4285,-80.3103 --50.4285,-80.3103 --49.49,-80.6725 --49.49,-80.6725 --50.4285,-80.3103 --50.4285,-80.3103 --49.49,-80.6725 --49.49,-80.6725 --48.5079,-80.8904 --48.5079,-80.8904 --49.49,-80.6725 --49.49,-80.6725 --48.5079,-80.8904 --48.5079,-80.8904 --46.1652,-80.9597 --46.1652,-80.9597 --48.5079,-80.8904 --48.5079,-80.8904 --46.1652,-80.9597 --46.1652,-80.9597 --45.3352,-80.96 --45.3352,-80.96 --46.1652,-80.9597 --46.1652,-80.9597 --45.3352,-80.96 --54.136,-72.3886 --54.1359,-73.6389 --50.1359,-73.6385 --54.136,-72.3886 --50.1359,-73.6385 --50.136,-72.3883 --54.1359,-73.6389 --54.1345,-74.6681 --50.1353,-74.5878 --54.1359,-73.6389 --50.1353,-74.5878 --50.1359,-73.6385 --54.1345,-74.6681 --54.0338,-75.6707 --50.0985,-74.9542 --54.1345,-74.6681 --50.0985,-74.9542 --50.1353,-74.5878 --54.0338,-75.6707 --53.7747,-76.6444 --50.0038,-75.3102 --54.0338,-75.6707 --50.0038,-75.3102 --50.0985,-74.9542 --53.7747,-76.6444 --53.3637,-77.5645 --49.8536,-75.6465 --53.7747,-76.6444 --49.8536,-75.6465 --50.0038,-75.3102 --53.3637,-77.5645 --52.8115,-78.4073 --49.6517,-75.9545 --53.3637,-77.5645 --49.6517,-75.9545 --49.8536,-75.6465 --52.8115,-78.4073 --52.0919,-79.1885 --49.3849,-76.2436 --52.8115,-78.4073 --49.3849,-76.2436 --49.6517,-75.9545 --52.0919,-79.1885 --51.3024,-79.8119 --49.0658,-76.4955 --52.0919,-79.1885 --49.0658,-76.4955 --49.3849,-76.2436 --51.3024,-79.8119 --50.4285,-80.3103 --48.7127,-76.697 --51.3024,-79.8119 --48.7127,-76.697 --49.0658,-76.4955 --50.4285,-80.3103 --49.49,-80.6725 --48.3334,-76.8433 --50.4285,-80.3103 --48.3334,-76.8433 --48.7127,-76.697 --49.49,-80.6725 --48.5079,-80.8904 --47.9365,-76.9314 --49.49,-80.6725 --47.9365,-76.9314 --48.3334,-76.8433 --48.5079,-80.8904 --46.1652,-80.9597 --46.1639,-76.9597 --48.5079,-80.8904 --46.1639,-76.9597 --47.9365,-76.9314 --46.1652,-80.9597 --45.3352,-80.96 --45.3339,-76.96 --46.1652,-80.9597 --45.3339,-76.96 --46.1639,-76.9597 --63.3323,-85.2681 --61.6796,-89.267 --61.6823,-85.267 --63.3323,-85.2681 --63.3296,-89.2681 --61.6796,-89.267 --61.6823,-85.267 --54.2896,-89.262 --54.2923,-85.262 --61.6823,-85.267 --61.6796,-89.267 --54.2896,-89.262 --54.2923,-85.262 --49.6147,-89.2588 --49.6174,-85.2588 --54.2923,-85.262 --54.2896,-89.262 --49.6147,-89.2588 --49.6174,-85.2588 --47.048,-89.2594 --47.0467,-85.2594 --49.6174,-85.2588 --49.6147,-89.2588 --47.048,-89.2594 --47.0467,-85.2594 --45.338,-89.26 --45.3367,-85.26 --47.0467,-85.2594 --47.048,-89.2594 --45.338,-89.26 --63.3325,-84.9681 --61.6823,-85.267 --61.6825,-84.967 --63.3325,-84.9681 --63.3323,-85.2681 --61.6823,-85.267 --61.6825,-84.967 --54.2923,-85.262 --54.2925,-84.962 --61.6825,-84.967 --61.6823,-85.267 --54.2923,-85.262 --54.2925,-84.962 --49.6174,-85.2588 --49.6176,-84.9588 --54.2925,-84.962 --54.2923,-85.262 --49.6174,-85.2588 --49.6176,-84.9588 --47.0467,-85.2594 --47.0466,-84.9594 --49.6176,-84.9588 --49.6174,-85.2588 --47.0467,-85.2594 --47.0466,-84.9594 --45.3367,-85.26 --45.3366,-84.96 --47.0466,-84.9594 --47.0467,-85.2594 --45.3367,-85.26 --63.3352,-80.9681 --61.6825,-84.967 --61.6852,-80.967 --63.3352,-80.9681 --63.3325,-84.9681 --61.6825,-84.967 --61.6852,-80.967 --54.2925,-84.962 --54.2952,-80.962 --61.6852,-80.967 --61.6825,-84.967 --54.2925,-84.962 --54.2952,-80.962 --49.6176,-84.9588 --49.6203,-80.9588 --54.2952,-80.962 --54.2925,-84.962 --49.6176,-84.9588 --49.6203,-80.9588 --47.0466,-84.9594 --47.0452,-80.9594 --49.6203,-80.9588 --49.6176,-84.9588 --47.0466,-84.9594 --47.0452,-80.9594 --45.3366,-84.96 --45.3352,-80.96 --47.0452,-80.9594 --47.0466,-84.9594 --45.3366,-84.96 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --63.3352,-80.9681 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --54.2952,-80.962 --54.2952,-80.962 --61.6852,-80.967 --61.6852,-80.967 --54.2952,-80.962 --54.2952,-80.962 --49.6203,-80.9588 --49.6203,-80.9588 --54.2952,-80.962 --54.2952,-80.962 --49.6203,-80.9588 --49.6203,-80.9588 --47.0452,-80.9594 --47.0452,-80.9594 --49.6203,-80.9588 --49.6203,-80.9588 --47.0452,-80.9594 --47.0452,-80.9594 --45.3352,-80.96 --45.3352,-80.96 --47.0452,-80.9594 --47.0452,-80.9594 --45.3352,-80.96 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --63.3352,-80.9681 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --54.2952,-80.962 --54.2952,-80.962 --61.6852,-80.967 --61.6852,-80.967 --54.2952,-80.962 --54.2952,-80.962 --49.6203,-80.9588 --49.6203,-80.9588 --54.2952,-80.962 --54.2952,-80.962 --49.6203,-80.9588 --49.6203,-80.9588 --47.0452,-80.9594 --47.0452,-80.9594 --49.6203,-80.9588 --49.6203,-80.9588 --47.0452,-80.9594 --47.0452,-80.9594 --45.3352,-80.96 --45.3352,-80.96 --47.0452,-80.9594 --47.0452,-80.9594 --45.3352,-80.96 --63.3352,-80.9681 --61.6852,-80.967 --61.6879,-76.967 --63.3352,-80.9681 --61.6879,-76.967 --63.3379,-76.9681 --61.6852,-80.967 --54.2952,-80.962 --54.2979,-76.962 --61.6852,-80.967 --54.2979,-76.962 --61.6879,-76.967 --54.2952,-80.962 --49.6203,-80.9588 --49.6231,-76.9588 --54.2952,-80.962 --49.6231,-76.9588 --54.2979,-76.962 --49.6203,-80.9588 --47.0452,-80.9594 --47.0439,-76.9594 --49.6203,-80.9588 --47.0439,-76.9594 --49.6231,-76.9588 --47.0452,-80.9594 --45.3352,-80.96 --45.3339,-76.96 --47.0452,-80.9594 --45.3339,-76.96 --47.0439,-76.9594 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --63.3352,-80.9681 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --59.7198,-80.9657 --59.7198,-80.9657 --61.6852,-80.967 --61.6852,-80.967 --59.7198,-80.9657 --59.7198,-80.9657 --58.6725,-80.8652 --58.6725,-80.8652 --59.7198,-80.9657 --59.7198,-80.9657 --58.6725,-80.8652 --58.6725,-80.8652 --57.663,-80.5687 --57.663,-80.5687 --58.6725,-80.8652 --58.6725,-80.8652 --57.663,-80.5687 --57.663,-80.5687 --56.7277,-80.0868 --56.7277,-80.0868 --57.663,-80.5687 --57.663,-80.5687 --56.7277,-80.0868 --56.7277,-80.0868 --55.9002,-79.4371 --55.9002,-79.4371 --56.7277,-80.0868 --56.7277,-80.0868 --55.9002,-79.4371 --55.9002,-79.4371 --55.2144,-78.6513 --55.2144,-78.6513 --55.9002,-79.4371 --55.9002,-79.4371 --55.2144,-78.6513 --55.2144,-78.6513 --54.692,-77.7714 --54.692,-77.7714 --55.2144,-78.6513 --55.2144,-78.6513 --54.692,-77.7714 --54.692,-77.7714 --54.3356,-76.8121 --54.3356,-76.8121 --54.692,-77.7714 --54.692,-77.7714 --54.3356,-76.8121 --54.3356,-76.8121 --54.1566,-75.8046 --54.1566,-75.8046 --54.3356,-76.8121 --54.3356,-76.8121 --54.1566,-75.8046 --54.1566,-75.8046 --54.1358,-73.9586 --54.1358,-73.9586 --54.1566,-75.8046 --54.1566,-75.8046 --54.1358,-73.9586 --54.1358,-73.9586 --54.136,-72.3886 --54.136,-72.3886 --54.1358,-73.9586 --54.1358,-73.9586 --54.136,-72.3886 --63.3352,-80.9681 --61.6852,-80.967 --61.6879,-76.967 --63.3352,-80.9681 --61.6879,-76.967 --63.3379,-76.9681 --61.6852,-80.967 --59.7198,-80.9657 --59.7225,-76.9657 --61.6852,-80.967 --59.7225,-76.9657 --61.6879,-76.967 --59.7198,-80.9657 --58.6725,-80.8652 --59.4306,-76.9377 --59.7198,-80.9657 --59.4306,-76.9377 --59.7225,-76.9657 --58.6725,-80.8652 --57.663,-80.5687 --59.1492,-76.855 --58.6725,-80.8652 --59.1492,-76.855 --59.4306,-76.9377 --57.663,-80.5687 --56.7277,-80.0868 --58.8885,-76.7207 --57.663,-80.5687 --58.8885,-76.7207 --59.1492,-76.855 --56.7277,-80.0868 --55.9002,-79.4371 --58.6579,-76.5396 --56.7277,-80.0868 --58.6579,-76.5396 --58.8885,-76.7207 --55.9002,-79.4371 --55.2144,-78.6513 --58.4565,-76.3084 --55.9002,-79.4371 --58.4565,-76.3084 --58.6579,-76.5396 --55.2144,-78.6513 --54.692,-77.7714 --58.3011,-76.0468 --55.2144,-78.6513 --58.3011,-76.0468 --58.4565,-76.3084 --54.692,-77.7714 --54.3356,-76.8121 --58.1951,-75.7615 --54.692,-77.7714 --58.1951,-75.7615 --58.3011,-76.0468 --54.3356,-76.8121 --54.1566,-75.8046 --58.1419,-75.4619 --54.3356,-76.8121 --58.1419,-75.4619 --58.1951,-75.7615 --54.1566,-75.8046 --54.1358,-73.9586 --58.1358,-73.959 --54.1566,-75.8046 --58.1358,-73.959 --58.1419,-75.4619 --54.1358,-73.9586 --54.136,-72.3886 --58.136,-72.389 --54.1358,-73.9586 --58.136,-72.389 --58.1358,-73.959 --63.3352,-80.9681 --61.6825,-84.967 --61.6852,-80.967 --63.3352,-80.9681 --63.3325,-84.9681 --61.6825,-84.967 --61.6852,-80.967 --59.7917,-84.9657 --59.7944,-80.9657 --61.6852,-80.967 --61.6825,-84.967 --59.7917,-84.9657 --59.7944,-80.9657 --58.0377,-84.7974 --58.7958,-80.8699 --59.7944,-80.9657 --59.7917,-84.9657 --58.0377,-84.7974 --58.7958,-80.8699 --56.347,-84.3008 --57.8332,-80.5872 --58.7958,-80.8699 --58.0377,-84.7974 --56.347,-84.3008 --57.8332,-80.5872 --54.7806,-83.4939 --56.9414,-80.1277 --57.8332,-80.5872 --56.347,-84.3008 --54.7806,-83.4939 --56.9414,-80.1277 --53.3947,-82.4056 --56.1524,-79.5082 --56.9414,-80.1277 --54.7806,-83.4939 --53.3947,-82.4056 --56.1524,-79.5082 --52.3011,-81.1786 --55.4605,-78.7255 --56.1524,-79.5082 --53.3947,-82.4056 --52.3011,-81.1786 --55.4605,-78.7255 --51.3983,-79.8012 --54.9082,-77.8828 --55.4605,-78.7255 --52.3011,-81.1786 --51.3983,-79.8012 --54.9082,-77.8828 --50.7264,-78.2976 --54.4971,-76.9628 --54.9082,-77.8828 --51.3983,-79.8012 --50.7264,-78.2976 --54.4971,-76.9628 --50.3026,-76.7062 --54.2379,-75.9892 --54.4971,-76.9628 --50.7264,-78.2976 --50.3026,-76.7062 --54.2379,-75.9892 --50.1379,-75.0675 --54.137,-74.9866 --54.2379,-75.9892 --50.3026,-76.7062 --50.1379,-75.0675 --54.137,-74.9866 --50.1358,-73.9583 --54.1358,-73.9586 --54.137,-74.9866 --50.1379,-75.0675 --50.1358,-73.9583 --54.1358,-73.9586 --50.136,-72.3883 --54.136,-72.3886 --54.1358,-73.9586 --50.1358,-73.9583 --50.136,-72.3883 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --63.3352,-80.9681 --63.3352,-80.9681 --61.6852,-80.967 --61.6852,-80.967 --59.7944,-80.9657 --59.7944,-80.9657 --61.6852,-80.967 --61.6852,-80.967 --59.7944,-80.9657 --59.7944,-80.9657 --58.7958,-80.8699 --58.7958,-80.8699 --59.7944,-80.9657 --59.7944,-80.9657 --58.7958,-80.8699 --58.7958,-80.8699 --57.8332,-80.5872 --57.8332,-80.5872 --58.7958,-80.8699 --58.7958,-80.8699 --57.8332,-80.5872 --57.8332,-80.5872 --56.9414,-80.1277 --56.9414,-80.1277 --57.8332,-80.5872 --57.8332,-80.5872 --56.9414,-80.1277 --56.9414,-80.1277 --56.1524,-79.5082 --56.1524,-79.5082 --56.9414,-80.1277 --56.9414,-80.1277 --56.1524,-79.5082 --56.1524,-79.5082 --55.4605,-78.7255 --55.4605,-78.7255 --56.1524,-79.5082 --56.1524,-79.5082 --55.4605,-78.7255 --55.4605,-78.7255 --54.9082,-77.8828 --54.9082,-77.8828 --55.4605,-78.7255 --55.4605,-78.7255 --54.9082,-77.8828 --54.9082,-77.8828 --54.4971,-76.9628 --54.4971,-76.9628 --54.9082,-77.8828 --54.9082,-77.8828 --54.4971,-76.9628 --54.4971,-76.9628 --54.2379,-75.9892 --54.2379,-75.9892 --54.4971,-76.9628 --54.4971,-76.9628 --54.2379,-75.9892 --54.2379,-75.9892 --54.137,-74.9866 --54.137,-74.9866 --54.2379,-75.9892 --54.2379,-75.9892 --54.137,-74.9866 --54.137,-74.9866 --54.1358,-73.9586 --54.1358,-73.9586 --54.137,-74.9866 --54.137,-74.9866 --54.1358,-73.9586 --54.1358,-73.9586 --54.136,-72.3886 --54.136,-72.3886 --54.1358,-73.9586 --54.1358,-73.9586 --54.136,-72.3886 --62.436,-72.3893 --62.4302,-72.3437 --62.4302,-72.3437 --62.436,-72.3893 --62.436,-72.3893 --62.4302,-72.3437 --62.4302,-72.3437 --62.4134,-72.3009 --62.4134,-72.3009 --62.4302,-72.3437 --62.4302,-72.3437 --62.4134,-72.3009 --62.4134,-72.3009 --62.3865,-72.2636 --62.3865,-72.2636 --62.4134,-72.3009 --62.4134,-72.3009 --62.3865,-72.2636 --62.3865,-72.2636 --62.5801,-72.4162 --62.5801,-72.4162 --62.3865,-72.2636 --62.3865,-72.2636 --62.5801,-72.4162 --62.5801,-72.4162 --62.7759,-72.536 --62.7759,-72.536 --62.5801,-72.4162 --62.5801,-72.4162 --62.7759,-72.536 --62.7759,-72.536 --62.99,-72.6188 --62.99,-72.6188 --62.7759,-72.536 --62.7759,-72.536 --62.99,-72.6188 --62.99,-72.6188 --63.2155,-72.6619 --63.2155,-72.6619 --62.99,-72.6188 --62.99,-72.6188 --63.2155,-72.6619 --63.2155,-72.6619 --63.3408,-72.6681 --63.3408,-72.6681 --63.2155,-72.6619 --63.2155,-72.6619 --63.3408,-72.6681 --62.436,-72.3893 --62.4302,-72.3437 --58.5545,-73.333 --62.436,-72.3893 --58.5545,-73.333 --58.436,-72.389 --62.4302,-72.3437 --62.4134,-72.3009 --58.9029,-74.2183 --62.4302,-72.3437 --58.9029,-74.2183 --58.5545,-73.333 --62.4134,-72.3009 --62.3865,-72.2636 --59.4595,-74.9899 --62.4134,-72.3009 --59.4595,-74.9899 --58.9029,-74.2183 --62.3865,-72.2636 --62.5801,-72.4162 --60.1945,-75.627 --62.3865,-72.2636 --60.1945,-75.627 --59.4595,-74.9899 --62.5801,-72.4162 --62.7759,-72.536 --61.0038,-76.122 --62.5801,-72.4162 --61.0038,-76.122 --60.1945,-75.627 --62.7759,-72.536 --62.99,-72.6188 --61.8885,-76.4641 --62.7759,-72.536 --61.8885,-76.4641 --61.0038,-76.122 --62.99,-72.6188 --63.2155,-72.6619 --62.8202,-76.6423 --62.99,-72.6188 --62.8202,-76.6423 --61.8885,-76.4641 --63.2155,-72.6619 --63.3408,-72.6681 --63.338,-76.6681 --63.2155,-72.6619 --63.338,-76.6681 --62.8202,-76.6423 --58.436,-72.389 --58.5545,-73.333 --58.2638,-73.4072 --58.436,-72.389 --58.2638,-73.4072 --58.136,-72.389 --58.5545,-73.333 --58.9029,-74.2183 --58.6396,-74.3621 --58.5545,-73.333 --58.6396,-74.3621 --58.2638,-73.4072 --58.9029,-74.2183 --59.4595,-74.9899 --59.24,-75.1944 --58.9029,-74.2183 --59.24,-75.1944 --58.6396,-74.3621 --59.4595,-74.9899 --60.1945,-75.627 --60.0156,-75.8678 --59.4595,-74.9899 --60.0156,-75.8678 --59.24,-75.1944 --60.1945,-75.627 --61.0038,-76.122 --60.8708,-76.3909 --60.1945,-75.627 --60.8708,-76.3909 --60.0156,-75.8678 --61.0038,-76.122 --61.8885,-76.4641 --61.8059,-76.7525 --61.0038,-76.122 --61.8059,-76.7525 --60.8708,-76.3909 --61.8885,-76.4641 --62.8202,-76.6423 --62.7906,-76.9408 --61.8885,-76.4641 --62.7906,-76.9408 --61.8059,-76.7525 --62.8202,-76.6423 --63.338,-76.6681 --63.3378,-76.9681 --62.8202,-76.6423 --63.3378,-76.9681 --62.7906,-76.9408 --94.5972,29.7176 --63.299,25.7032 --63.2972,29.7032 --94.5972,29.7176 --94.599,25.7176 --63.299,25.7032 --94.597,30.0176 --63.2972,29.7032 --63.2971,30.0032 --94.597,30.0176 --94.5972,29.7176 --63.2972,29.7032 --94.5952,34.0176 --63.2971,30.0032 --63.2952,34.0032 --94.5952,34.0176 --94.597,30.0176 --63.2971,30.0032 --94.5952,34.0176 --63.2952,34.0032 --63.2952,34.0032 --94.5952,34.0176 --94.5952,34.0176 --63.2952,34.0032 --94.5952,34.0176 --63.2952,34.0032 --63.2934,38.0032 --94.5952,34.0176 --63.2934,38.0032 --94.5934,38.0176 --94.5934,38.0176 --63.2934,38.0032 --63.2932,38.3032 --94.5934,38.0176 --63.2932,38.3032 --94.5932,38.3176 --94.5932,38.3176 --63.2932,38.3032 --63.2914,42.3032 --94.5932,38.3176 --63.2914,42.3032 --94.5914,42.3176 --103.447,24.3313 --103.447,25.3413 --103.447,25.3413 --103.447,24.3313 --103.447,24.3313 --103.447,25.3413 --103.447,25.3413 --103.449,31.978 --103.449,31.978 --103.447,25.3413 --103.447,25.3413 --103.449,31.978 --103.449,31.978 --103.449,33.5513 --103.449,33.5513 --103.449,31.978 --103.449,31.978 --103.449,33.5513 --103.449,33.5513 --103.45,40.5713 --103.45,40.5713 --103.449,33.5513 --103.449,33.5513 --103.45,40.5713 --103.45,40.5713 --103.451,42.3313 --103.451,42.3313 --103.45,40.5713 --103.45,40.5713 --103.451,42.3313 --103.447,24.3313 --103.447,25.3413 --107.447,25.3404 --103.447,24.3313 --107.447,25.3404 --107.447,24.3304 --103.447,25.3413 --103.449,31.978 --107.449,31.9771 --103.447,25.3413 --107.449,31.9771 --107.447,25.3404 --103.449,31.978 --103.449,33.5513 --107.449,33.5504 --103.449,31.978 --107.449,33.5504 --107.449,31.9771 --103.449,33.5513 --103.45,40.5713 --107.45,40.5704 --103.449,33.5513 --107.45,40.5704 --107.449,33.5504 --103.45,40.5713 --103.451,42.3313 --107.451,42.3304 --103.45,40.5713 --107.451,42.3304 --107.45,40.5704 --107.447,24.3304 --107.447,25.3404 --107.747,25.3404 --107.447,24.3304 --107.747,25.3404 --107.747,24.3304 --107.447,25.3404 --107.449,31.9771 --107.749,31.977 --107.447,25.3404 --107.749,31.977 --107.747,25.3404 --107.449,31.9771 --107.449,33.5504 --107.749,33.5504 --107.449,31.9771 --107.749,33.5504 --107.749,31.977 --107.449,33.5504 --107.45,40.5704 --107.75,40.5704 --107.449,33.5504 --107.75,40.5704 --107.749,33.5504 --107.45,40.5704 --107.451,42.3304 --107.751,42.3304 --107.45,40.5704 --107.751,42.3304 --107.75,40.5704 --107.747,24.3304 --107.747,25.3404 --111.747,25.3395 --107.747,24.3304 --111.747,25.3395 --111.747,24.3295 --107.747,25.3404 --107.749,31.977 --111.749,31.9761 --107.747,25.3404 --111.749,31.9761 --111.747,25.3395 --107.749,31.977 --107.749,33.5504 --111.749,33.5495 --107.749,31.977 --111.749,33.5495 --111.749,31.9761 --107.749,33.5504 --107.75,40.5704 --111.75,40.5695 --107.749,33.5504 --111.75,40.5695 --111.749,33.5495 --107.75,40.5704 --107.751,42.3304 --111.751,42.3295 --107.75,40.5704 --111.751,42.3295 --111.75,40.5695 --103.447,24.3313 --99.447,25.3423 --103.447,25.3413 --103.447,24.3313 --99.4468,24.3323 --99.447,25.3423 --103.447,25.3413 --99.4485,31.9789 --103.449,31.978 --103.447,25.3413 --99.447,25.3423 --99.4485,31.9789 --103.449,31.978 --99.4489,33.5523 --103.449,33.5513 --103.449,31.978 --99.4485,31.9789 --99.4489,33.5523 --103.449,33.5513 --99.4505,40.5723 --103.45,40.5713 --103.449,33.5513 --99.4489,33.5523 --99.4505,40.5723 --103.45,40.5713 --99.4509,42.3323 --103.451,42.3313 --103.45,40.5713 --99.4505,40.5723 --99.4509,42.3323 --103.447,24.3313 --103.447,25.3413 --103.447,25.3413 --103.447,24.3313 --103.447,24.3313 --103.447,25.3413 --103.447,25.3413 --103.449,31.978 --103.449,31.978 --103.447,25.3413 --103.447,25.3413 --103.449,31.978 --103.449,31.978 --103.449,33.5513 --103.449,33.5513 --103.449,31.978 --103.449,31.978 --103.449,33.5513 --103.449,33.5513 --103.45,40.5713 --103.45,40.5713 --103.449,33.5513 --103.449,33.5513 --103.45,40.5713 --103.45,40.5713 --103.451,42.3313 --103.451,42.3313 --103.45,40.5713 --103.45,40.5713 --103.451,42.3313 --103.447,24.3313 --99.447,25.3423 --103.447,25.3413 --103.447,24.3313 --99.4468,24.3323 --99.447,25.3423 --103.447,25.3413 --99.4409,26.1553 --103.436,26.3543 --103.447,25.3413 --99.447,25.3423 --99.4409,26.1553 --103.436,26.3543 --99.3744,26.7589 --103.317,27.4348 --103.436,26.3543 --99.4409,26.1553 --99.3744,26.7589 --103.317,27.4348 --99.2361,27.3502 --103.069,28.4932 --103.317,27.4348 --99.3744,26.7589 --99.2361,27.3502 --103.069,28.4932 --99.028,27.9207 --102.697,29.5143 --103.069,28.4932 --99.2361,27.3502 --99.028,27.9207 --102.697,29.5143 --98.7531,28.4622 --102.205,30.4835 --102.697,29.5143 --99.028,27.9207 --98.7531,28.4622 --102.205,30.4835 --98.3293,29.099 --101.615,31.38 --102.205,30.4835 --98.7531,28.4622 --98.3293,29.099 --101.615,31.38 --98.0975,29.3788 --100.95,32.1828 --101.615,31.38 --98.3293,29.099 --98.0975,29.3788 --100.95,32.1828 --97.8218,29.6153 --100.159,32.8615 --100.95,32.1828 --98.0975,29.3788 --97.8218,29.6153 --100.159,32.8615 --97.51,29.8018 --99.2642,33.3966 --100.159,32.8615 --97.8218,29.6153 --97.51,29.8018 --99.2642,33.3966 --97.1711,29.9328 --98.2919,33.7726 --99.2642,33.3966 --97.51,29.8018 --97.1711,29.9328 --98.2919,33.7726 --96.815,30.0046 --97.27,33.9786 --98.2919,33.7726 --97.1711,29.9328 --96.815,30.0046 --97.27,33.9786 --94.857,30.0177 --94.8552,34.0177 --97.27,33.9786 --96.815,30.0046 --94.857,30.0177 --94.8552,34.0177 --94.597,30.0176 --94.5952,34.0176 --94.8552,34.0177 --94.857,30.0177 --94.597,30.0176 --103.447,24.3313 --103.447,25.3413 --103.447,25.3413 --103.447,24.3313 --103.447,24.3313 --103.447,25.3413 --103.447,25.3413 --103.436,26.3543 --103.436,26.3543 --103.447,25.3413 --103.447,25.3413 --103.436,26.3543 --103.436,26.3543 --103.317,27.4348 --103.317,27.4348 --103.436,26.3543 --103.436,26.3543 --103.317,27.4348 --103.317,27.4348 --103.069,28.4932 --103.069,28.4932 --103.317,27.4348 --103.317,27.4348 --103.069,28.4932 --103.069,28.4932 --102.697,29.5143 --102.697,29.5143 --103.069,28.4932 --103.069,28.4932 --102.697,29.5143 --102.697,29.5143 --102.205,30.4835 --102.205,30.4835 --102.697,29.5143 --102.697,29.5143 --102.205,30.4835 --102.205,30.4835 --101.615,31.38 --101.615,31.38 --102.205,30.4835 --102.205,30.4835 --101.615,31.38 --101.615,31.38 --100.95,32.1828 --100.95,32.1828 --101.615,31.38 --101.615,31.38 --100.95,32.1828 --100.95,32.1828 --100.159,32.8615 --100.159,32.8615 --100.95,32.1828 --100.95,32.1828 --100.159,32.8615 --100.159,32.8615 --99.2642,33.3966 --99.2642,33.3966 --100.159,32.8615 --100.159,32.8615 --99.2642,33.3966 --99.2642,33.3966 --98.2919,33.7726 --98.2919,33.7726 --99.2642,33.3966 --99.2642,33.3966 --98.2919,33.7726 --98.2919,33.7726 --97.27,33.9786 --97.27,33.9786 --98.2919,33.7726 --98.2919,33.7726 --97.27,33.9786 --97.27,33.9786 --94.8552,34.0177 --94.8552,34.0177 --97.27,33.9786 --97.27,33.9786 --94.8552,34.0177 --94.8552,34.0177 --94.5952,34.0176 --94.5952,34.0176 --94.8552,34.0177 --94.8552,34.0177 --94.5952,34.0176 --103.447,24.3313 --103.447,25.3416 --103.447,25.3416 --103.447,24.3313 --103.447,24.3313 --103.447,25.3416 --103.447,25.3416 --103.447,26.4236 --103.447,26.4236 --103.447,25.3416 --103.447,25.3416 --103.447,26.4236 --103.447,26.4236 --103.381,27.4459 --103.381,27.4459 --103.447,26.4236 --103.447,26.4236 --103.381,27.4459 --103.381,27.4459 --103.183,28.4511 --103.183,28.4511 --103.381,27.4459 --103.381,27.4459 --103.183,28.4511 --103.183,28.4511 --102.856,29.4221 --102.856,29.4221 --103.183,28.4511 --103.183,28.4511 --102.856,29.4221 --102.856,29.4221 --102.406,30.3425 --102.406,30.3425 --102.856,29.4221 --102.856,29.4221 --102.406,30.3425 --102.406,30.3425 --101.84,31.1967 --101.84,31.1967 --102.406,30.3425 --102.406,30.3425 --101.84,31.1967 --101.84,31.1967 --101.179,31.9589 --101.179,31.9589 --101.84,31.1967 --101.84,31.1967 --101.179,31.9589 --101.179,31.9589 --100.388,32.6435 --100.388,32.6435 --101.179,31.9589 --101.179,31.9589 --100.388,32.6435 --100.388,32.6435 --99.5038,33.2022 --99.5038,33.2022 --100.388,32.6435 --100.388,32.6435 --99.5038,33.2022 --99.5038,33.2022 --98.5458,33.6224 --98.5458,33.6224 --99.5038,33.2022 --99.5038,33.2022 --98.5458,33.6224 --98.5458,33.6224 --97.5358,33.8948 --97.5358,33.8948 --98.5458,33.6224 --98.5458,33.6224 --97.5358,33.8948 --97.5358,33.8948 --96.4964,34.0132 --96.4964,34.0132 --97.5358,33.8948 --97.5358,33.8948 --96.4964,34.0132 --96.4964,34.0132 --94.5952,34.0176 --94.5952,34.0176 --96.4964,34.0132 --96.4964,34.0132 --94.5952,34.0176 --103.447,24.3313 --103.447,25.3416 --107.447,25.3407 --103.447,24.3313 --107.447,25.3407 --107.447,24.3304 --103.447,25.3416 --103.447,26.4236 --107.447,26.4227 --103.447,25.3416 --107.447,26.4227 --107.447,25.3407 --103.447,26.4236 --103.381,27.4459 --107.347,27.9636 --103.447,26.4236 --107.347,27.9636 --107.447,26.4227 --103.381,27.4459 --103.183,28.4511 --107.048,29.4785 --103.381,27.4459 --107.048,29.4785 --107.347,27.9636 --103.183,28.4511 --102.856,29.4221 --106.556,30.942 --103.183,28.4511 --106.556,30.942 --107.048,29.4785 --102.856,29.4221 --102.406,30.3425 --105.877,32.3292 --102.856,29.4221 --105.877,32.3292 --106.556,30.942 --102.406,30.3425 --101.84,31.1967 --105.025,33.6168 --102.406,30.3425 --105.025,33.6168 --105.877,32.3292 --101.84,31.1967 --101.179,31.9589 --104.016,34.7789 --101.84,31.1967 --104.016,34.7789 --105.025,33.6168 --101.179,31.9589 --100.388,32.6435 --102.772,35.8557 --101.179,31.9589 --102.772,35.8557 --104.016,34.7789 --100.388,32.6435 --99.5038,33.2022 --101.381,36.7345 --100.388,32.6435 --101.381,36.7345 --102.772,35.8557 --99.5038,33.2022 --98.5458,33.6224 --99.8737,37.3956 --99.5038,33.2022 --99.8737,37.3956 --101.381,36.7345 --98.5458,33.6224 --97.5358,33.8948 --98.285,37.824 --98.5458,33.6224 --98.285,37.824 --99.8737,37.3956 --97.5358,33.8948 --96.4964,34.0132 --96.65,38.0102 --97.5358,33.8948 --96.65,38.0102 --98.285,37.824 --96.4964,34.0132 --94.5952,34.0176 --94.5934,38.0176 --96.4964,34.0132 --94.5934,38.0176 --96.65,38.0102 --95.1468,24.3332 --95.1214,24.6159 --95.1214,24.6159 --95.1468,24.3332 --95.1468,24.3332 --95.1214,24.6159 --95.1214,24.6159 --95.0457,24.8895 --95.0457,24.8895 --95.1214,24.6159 --95.1214,24.6159 --95.0457,24.8895 --95.0457,24.8895 --94.9223,25.1452 --94.9223,25.1452 --95.0457,24.8895 --95.0457,24.8895 --94.9223,25.1452 --94.9223,25.1452 --94.3955,25.8589 --94.3955,25.8589 --94.9223,25.1452 --94.9223,25.1452 --94.3955,25.8589 --94.3955,25.8589 --94.46,25.7932 --94.46,25.7932 --94.3955,25.8589 --94.3955,25.8589 --94.46,25.7932 --94.46,25.7932 --94.5391,25.7463 --94.5391,25.7463 --94.46,25.7932 --94.46,25.7932 --94.5391,25.7463 --94.5391,25.7463 --94.6276,25.7213 --94.6276,25.7213 --94.5391,25.7463 --94.5391,25.7463 --94.6276,25.7213 --94.6276,25.7213 --94.599,25.7176 --94.599,25.7176 --94.6276,25.7213 --94.6276,25.7213 --94.599,25.7176 --95.1468,24.3332 --95.1214,24.6159 --99.0569,25.3312 --95.1468,24.3332 --99.0569,25.3312 --99.1468,24.3323 --95.1214,24.6159 --95.0457,24.8895 --98.7896,26.2978 --95.1214,24.6159 --98.7896,26.2978 --99.0569,25.3312 --95.0457,24.8895 --94.9223,25.1452 --98.3536,27.2009 --95.0457,24.8895 --98.3536,27.2009 --98.7896,26.2978 --94.9223,25.1452 --94.3955,25.8589 --97.59,28.2663 --94.9223,25.1452 --97.59,28.2663 --98.3536,27.2009 --94.3955,25.8589 --94.46,25.7932 --96.9281,28.9409 --94.3955,25.8589 --96.9281,28.9409 --97.59,28.2663 --94.46,25.7932 --94.5391,25.7463 --96.1151,29.4228 --94.46,25.7932 --96.1151,29.4228 --96.9281,28.9409 --94.5391,25.7463 --94.6276,25.7213 --95.2055,29.6794 --94.5391,25.7463 --95.2055,29.6794 --96.1151,29.4228 --94.6276,25.7213 --94.599,25.7176 --94.5972,29.7176 --94.6276,25.7213 --94.5972,29.7176 --95.2055,29.6794 --99.1468,24.3323 --99.0569,25.3312 --99.3521,25.3848 --99.1468,24.3323 --99.3521,25.3848 --99.4468,24.3323 --99.0569,25.3312 --98.7896,26.2978 --99.0704,26.4034 --99.0569,25.3312 --99.0704,26.4034 --99.3521,25.3848 --98.7896,26.2978 --98.3536,27.2009 --98.6109,27.3551 --98.7896,26.2978 --98.6109,27.3551 --99.0704,26.4034 --98.3536,27.2009 --97.59,28.2663 --97.8296,28.4468 --98.3536,27.2009 --97.8296,28.4468 --98.6109,27.3551 --97.59,28.2663 --96.9281,28.9409 --97.1132,29.177 --97.59,28.2663 --97.1132,29.177 --97.8296,28.4468 --96.9281,28.9409 --96.1151,29.4228 --96.2333,29.6985 --96.9281,28.9409 --96.2333,29.6985 --97.1132,29.177 --96.1151,29.4228 --95.2055,29.6794 --95.2488,29.9762 --96.1151,29.4228 --95.2488,29.9762 --96.2333,29.6985 --95.2055,29.6794 --94.5972,29.7176 --94.597,30.0176 --95.2055,29.6794 --94.597,30.0176 --95.2488,29.9762 --94.5952,34.0176 --97.0937,34.0187 --97.0937,34.0187 --94.5952,34.0176 --94.5952,34.0176 --97.0937,34.0187 --97.0937,34.0187 --98.1085,34.0853 --98.1085,34.0853 --97.0937,34.0187 --97.0937,34.0187 --98.1085,34.0853 --98.1085,34.0853 --99.1061,34.2828 --99.1061,34.2828 --98.1085,34.0853 --98.1085,34.0853 --99.1061,34.2828 --99.1061,34.2828 --100.07,34.6079 --100.07,34.6079 --99.1061,34.2828 --99.1061,34.2828 --100.07,34.6079 --100.07,34.6079 --100.983,35.0553 --100.983,35.0553 --100.07,34.6079 --100.07,34.6079 --100.983,35.0553 --100.983,35.0553 --101.823,35.6232 --101.823,35.6232 --100.983,35.0553 --100.983,35.0553 --101.823,35.6232 --101.823,35.6232 --102.54,36.3729 --102.54,36.3729 --101.823,35.6232 --101.823,35.6232 --102.54,36.3729 --102.54,36.3729 --103.064,37.2622 --103.064,37.2622 --102.54,36.3729 --102.54,36.3729 --103.064,37.2622 --103.064,37.2622 --103.371,38.2476 --103.371,38.2476 --103.064,37.2622 --103.064,37.2622 --103.371,38.2476 --103.371,38.2476 --103.45,40.5713 --103.45,40.5713 --103.371,38.2476 --103.371,38.2476 --103.45,40.5713 --103.45,40.5713 --103.451,42.3313 --103.451,42.3313 --103.45,40.5713 --103.45,40.5713 --103.451,42.3313 --94.5952,34.0176 --97.0937,34.0187 --97.0955,30.0187 --94.5952,34.0176 --97.0955,30.0187 --94.597,30.0176 --97.0937,34.0187 --98.1085,34.0853 --98.6288,30.1192 --97.0937,34.0187 --98.6288,30.1192 --97.0955,30.0187 --98.1085,34.0853 --99.1061,34.2828 --100.136,30.4177 --98.1085,34.0853 --100.136,30.4177 --98.6288,30.1192 --99.1061,34.2828 --100.07,34.6079 --101.592,30.909 --99.1061,34.2828 --101.592,30.909 --100.136,30.4177 --100.07,34.6079 --100.983,35.0553 --102.972,31.5849 --100.07,34.6079 --102.972,31.5849 --101.592,30.909 --100.983,35.0553 --101.823,35.6232 --104.376,32.5439 --100.983,35.0553 --104.376,32.5439 --102.972,31.5849 --101.823,35.6232 --102.54,36.3729 --105.73,33.9603 --101.823,35.6232 --105.73,33.9603 --104.376,32.5439 --102.54,36.3729 --103.064,37.2622 --106.72,35.6405 --102.54,36.3729 --106.72,35.6405 --105.73,33.9603 --103.064,37.2622 --103.371,38.2476 --107.301,37.5022 --103.064,37.2622 --107.301,37.5022 --106.72,35.6405 --103.371,38.2476 --103.45,40.5713 --107.45,40.5704 --103.371,38.2476 --107.45,40.5704 --107.301,37.5022 --103.45,40.5713 --103.451,42.3313 --107.451,42.3304 --103.45,40.5713 --107.451,42.3304 --107.45,40.5704 --103.451,42.3313 --103.451,41.2511 --103.451,41.2511 --103.451,42.3313 --103.451,42.3313 --103.451,41.2511 --103.451,41.2511 --103.45,39.6618 --103.45,39.6618 --103.451,41.2511 --103.451,41.2511 --103.45,39.6618 --103.45,39.6618 --103.355,38.6649 --103.355,38.6649 --103.45,39.6618 --103.45,39.6618 --103.355,38.6649 --103.355,38.6649 --103.073,37.7038 --103.073,37.7038 --103.355,38.6649 --103.355,38.6649 --103.073,37.7038 --103.073,37.7038 --102.615,36.8133 --102.615,36.8133 --103.073,37.7038 --103.073,37.7038 --102.615,36.8133 --102.615,36.8133 --101.997,36.0253 --101.997,36.0253 --102.615,36.8133 --102.615,36.8133 --101.997,36.0253 --101.997,36.0253 --101.22,35.3491 --101.22,35.3491 --101.997,36.0253 --101.997,36.0253 --101.22,35.3491 --101.22,35.3491 --100.348,34.8045 --100.348,34.8045 --101.22,35.3491 --101.22,35.3491 --100.348,34.8045 --100.348,34.8045 --99.4047,34.3963 --99.4047,34.3963 --100.348,34.8045 --100.348,34.8045 --99.4047,34.3963 --99.4047,34.3963 --98.4105,34.1337 --98.4105,34.1337 --99.4047,34.3963 --99.4047,34.3963 --98.4105,34.1337 --98.4105,34.1337 --97.3884,34.0226 --97.3884,34.0226 --98.4105,34.1337 --98.4105,34.1337 --97.3884,34.0226 --97.3884,34.0226 --94.9752,34.0178 --94.9752,34.0178 --97.3884,34.0226 --97.3884,34.0226 --94.9752,34.0178 --94.9752,34.0178 --94.5952,34.0176 --94.5952,34.0176 --94.9752,34.0178 --94.9752,34.0178 --94.5952,34.0176 --103.451,42.3313 --103.451,41.2511 --99.4506,41.252 --103.451,42.3313 --99.4506,41.252 --99.4509,42.3323 --103.451,41.2511 --103.45,39.6618 --99.4503,39.6627 --103.451,41.2511 --99.4503,39.6627 --99.4506,41.252 --103.45,39.6618 --103.355,38.6649 --99.4272,39.4212 --103.45,39.6618 --99.4272,39.4212 --99.4503,39.6627 --103.355,38.6649 --103.073,37.7038 --99.3589,39.1883 --103.355,38.6649 --99.3589,39.1883 --99.4272,39.4212 --103.073,37.7038 --102.615,36.8133 --99.2479,38.9726 --103.073,37.7038 --99.2479,38.9726 --99.3589,39.1883 --102.615,36.8133 --101.997,36.0253 --99.0981,38.7817 --102.615,36.8133 --99.0981,38.7817 --99.2479,38.9726 --101.997,36.0253 --101.22,35.3491 --98.8533,38.5735 --101.997,36.0253 --98.8533,38.5735 --99.0981,38.7817 --101.22,35.3491 --100.348,34.8045 --98.4897,38.3464 --101.22,35.3491 --98.4897,38.3464 --98.8533,38.5735 --100.348,34.8045 --99.4047,34.3963 --98.0961,38.1762 --100.348,34.8045 --98.0961,38.1762 --98.4897,38.3464 --99.4047,34.3963 --98.4105,34.1337 --97.6816,38.0667 --99.4047,34.3963 --97.6816,38.0667 --98.0961,38.1762 --98.4105,34.1337 --97.3884,34.0226 --97.2553,38.0203 --98.4105,34.1337 --97.2553,38.0203 --97.6816,38.0667 --97.3884,34.0226 --94.9752,34.0178 --94.9734,38.0178 --97.3884,34.0226 --94.9734,38.0178 --97.2553,38.0203 --94.9752,34.0178 --94.5952,34.0176 --94.5934,38.0176 --94.9752,34.0178 --94.5934,38.0176 --94.9734,38.0178 -89.4042,-24.7794 -89.6037,-23.7796 -89.3097,-23.8392 -89.4042,-24.7794 -89.7042,-24.7793 -89.6037,-23.7796 -89.3097,-23.8392 -89.3065,-22.8197 -89.0302,-22.9366 -89.3097,-23.8392 -89.6037,-23.7796 -89.3065,-22.8197 -89.0302,-22.9366 -88.8245,-21.938 -88.577,-22.1075 -89.0302,-22.9366 -89.3065,-22.8197 -88.8245,-21.938 -88.577,-22.1075 -87.8737,-20.8283 -87.653,-21.0315 -88.577,-22.1075 -88.8245,-21.938 -87.8737,-20.8283 -87.653,-21.0315 -87.0959,-20.1572 -86.9273,-20.4053 -87.653,-21.0315 -87.8737,-20.8283 -87.0959,-20.1572 -86.9273,-20.4053 -86.1856,-19.681 -86.078,-19.961 -86.9273,-20.4053 -87.0959,-20.1572 -86.1856,-19.681 -86.078,-19.961 -85.1907,-19.4249 -85.1497,-19.7221 -86.078,-19.961 -86.1856,-19.681 -85.1907,-19.4249 -85.1497,-19.7221 -84.5224,-19.383 -84.5222,-19.683 -85.1497,-19.7221 -85.1907,-19.4249 -84.5224,-19.383 -85.4042,-24.7805 -89.3097,-23.8392 -85.3896,-24.6349 -85.4042,-24.7805 -89.4042,-24.7794 -89.3097,-23.8392 -85.3896,-24.6349 -89.0302,-22.9366 -85.3464,-24.4952 -85.3896,-24.6349 -89.3097,-23.8392 -89.0302,-22.9366 -85.3464,-24.4952 -88.577,-22.1075 -85.2762,-24.3669 -85.3464,-24.4952 -89.0302,-22.9366 -88.577,-22.1075 -85.2762,-24.3669 -87.653,-21.0315 -84.7096,-23.7401 -85.2762,-24.3669 -88.577,-22.1075 -87.653,-21.0315 -84.7096,-23.7401 -86.9273,-20.4053 -84.6789,-23.7136 -84.7096,-23.7401 -87.653,-21.0315 -86.9273,-20.4053 -84.6789,-23.7136 -86.078,-19.961 -84.643,-23.6948 -84.6789,-23.7136 -86.9273,-20.4053 -86.078,-19.961 -84.643,-23.6948 -85.1497,-19.7221 -84.6037,-23.6847 -84.643,-23.6948 -86.078,-19.961 -85.1497,-19.7221 -84.6037,-23.6847 -84.5222,-19.683 -84.5197,-23.683 -84.6037,-23.6847 -85.1497,-19.7221 -84.5222,-19.683 -85.4042,-24.7805 -85.3896,-24.6349 -85.3896,-24.6349 -85.4042,-24.7805 -85.4042,-24.7805 -85.3896,-24.6349 -85.3896,-24.6349 -85.3464,-24.4952 -85.3464,-24.4952 -85.3896,-24.6349 -85.3896,-24.6349 -85.3464,-24.4952 -85.3464,-24.4952 -85.2762,-24.3669 -85.2762,-24.3669 -85.3464,-24.4952 -85.3464,-24.4952 -85.2762,-24.3669 -85.2762,-24.3669 -84.7096,-23.7401 -84.7096,-23.7401 -85.2762,-24.3669 -85.2762,-24.3669 -84.7096,-23.7401 -84.7096,-23.7401 -84.6789,-23.7136 -84.6789,-23.7136 -84.7096,-23.7401 -84.7096,-23.7401 -84.6789,-23.7136 -84.6789,-23.7136 -84.643,-23.6948 -84.643,-23.6948 -84.6789,-23.7136 -84.6789,-23.7136 -84.643,-23.6948 -84.643,-23.6948 -84.6037,-23.6847 -84.6037,-23.6847 -84.643,-23.6948 -84.643,-23.6948 -84.6037,-23.6847 -84.6037,-23.6847 -84.5197,-23.683 -84.5197,-23.683 -84.6037,-23.6847 -84.6037,-23.6847 -84.5197,-23.683 --99.1509,42.3321 --99.3563,41.3375 --99.0635,41.403 --99.1509,42.3321 --99.4509,42.3321 --99.3563,41.3375 --99.0635,41.403 --99.008,40.384 --98.7419,40.5225 --99.0635,41.403 --99.3563,41.3375 --99.008,40.384 --98.7419,40.5225 --98.4262,39.552 --98.2047,39.7543 --98.7419,40.5225 --99.008,40.384 --98.4262,39.552 --98.2047,39.7543 --97.6496,38.8888 --97.4808,39.1368 --98.2047,39.7543 --98.4262,39.552 --97.6496,38.8888 --97.4808,39.1368 --96.7676,38.4097 --96.6515,38.6863 --97.4808,39.1368 --97.6496,38.8888 --96.7676,38.4097 --96.6515,38.6863 --95.808,38.1155 --95.7491,38.4096 --96.6515,38.6863 --96.7676,38.4097 --95.808,38.1155 --95.7491,38.4096 --94.6834,38.0176 --94.6832,38.3176 --95.7491,38.4096 --95.808,38.1155 --94.6834,38.0176 --94.6832,38.3176 --94.5934,38.0176 --94.5932,38.3176 --94.6832,38.3176 --94.6834,38.0176 --94.5934,38.0176 --95.1509,42.333 --99.0635,41.403 --95.1601,42.2768 --95.1509,42.333 --99.1509,42.3321 --99.0635,41.403 --95.1601,42.2768 --98.7419,40.5225 --95.1943,42.3705 --95.1601,42.2768 --99.0635,41.403 --98.7419,40.5225 --95.1943,42.3705 --98.2047,39.7543 --95.2515,42.4522 --95.1943,42.3705 --98.7419,40.5225 --98.2047,39.7543 --95.2515,42.4522 --97.4808,39.1368 --95.2304,42.4437 --95.2515,42.4522 --98.2047,39.7543 --97.4808,39.1368 --95.2304,42.4437 --96.6515,38.6863 --95.1028,42.3744 --95.2304,42.4437 --97.4808,39.1368 --96.6515,38.6863 --95.1028,42.3744 --95.7491,38.4096 --94.964,42.3318 --95.1028,42.3744 --96.6515,38.6863 --95.7491,38.4096 --94.964,42.3318 --94.6832,38.3176 --94.6814,42.3176 --94.964,42.3318 --95.7491,38.4096 --94.6832,38.3176 --94.6814,42.3176 --94.5932,38.3176 --94.5914,42.3176 --94.6814,42.3176 --94.6832,38.3176 --94.5932,38.3176 --95.1509,42.333 --95.1601,42.2768 --95.1601,42.2768 --95.1509,42.333 --95.1509,42.333 --95.1601,42.2768 --95.1601,42.2768 --95.1943,42.3705 --95.1943,42.3705 --95.1601,42.2768 --95.1601,42.2768 --95.1943,42.3705 --95.1943,42.3705 --95.2515,42.4522 --95.2515,42.4522 --95.1943,42.3705 --95.1943,42.3705 --95.2515,42.4522 --95.2515,42.4522 --95.2304,42.4437 --95.2304,42.4437 --95.2515,42.4522 --95.2515,42.4522 --95.2304,42.4437 --95.2304,42.4437 --95.1028,42.3744 --95.1028,42.3744 --95.2304,42.4437 --95.2304,42.4437 --95.1028,42.3744 --95.1028,42.3744 --94.964,42.3318 --94.964,42.3318 --95.1028,42.3744 --95.1028,42.3744 --94.964,42.3318 --94.964,42.3318 --94.6814,42.3176 --94.6814,42.3176 --94.964,42.3318 --94.964,42.3318 --94.6814,42.3176 --94.6814,42.3176 --94.5914,42.3176 --94.5914,42.3176 --94.6814,42.3176 --94.6814,42.3176 --94.5914,42.3176 -93.7042,-24.7786 -97.704,-23.7777 -93.704,-23.7786 -93.7042,-24.7786 -97.7042,-24.7777 -97.704,-23.7777 -93.704,-23.7786 -97.7038,-22.59 -93.7038,-22.5909 -93.704,-23.7786 -97.704,-23.7777 -97.7038,-22.59 -93.7038,-22.5909 -97.5905,-20.9805 -93.6298,-21.5396 -93.7038,-22.5909 -97.7038,-22.59 -97.5905,-20.9805 -93.6298,-21.5396 -97.2538,-19.4026 -93.4099,-20.5088 -93.6298,-21.5396 -97.5905,-20.9805 -97.2538,-19.4026 -93.4099,-20.5088 -96.7002,-17.887 -93.0482,-19.5189 -93.4099,-20.5088 -97.2538,-19.4026 -96.7002,-17.887 -93.0482,-19.5189 -95.9406,-16.4636 -92.552,-18.5891 -93.0482,-19.5189 -96.7002,-17.887 -95.9406,-16.4636 -92.552,-18.5891 -94.9897,-15.16 -91.9309,-17.7376 -92.552,-18.5891 -95.9406,-16.4636 -94.9897,-15.16 -91.9309,-17.7376 -93.8196,-13.9691 -91.196,-16.9885 -91.9309,-17.7376 -94.9897,-15.16 -93.8196,-13.9691 -91.196,-16.9885 -92.4633,-12.969 -90.3543,-16.3679 -91.196,-16.9885 -93.8196,-13.9691 -92.4633,-12.969 -90.3543,-16.3679 -90.965,-12.1978 -89.4244,-15.8892 -90.3543,-16.3679 -92.4633,-12.969 -90.965,-12.1978 -89.4244,-15.8892 -89.363,-11.6751 -88.4302,-15.5649 -89.4244,-15.8892 -90.965,-12.1978 -89.363,-11.6751 -88.4302,-15.5649 -87.6981,-11.4144 -87.397,-15.403 -88.4302,-15.5649 -89.363,-11.6751 -87.6981,-11.4144 -87.397,-15.403 -85.6772,-11.3837 -85.6748,-15.3837 -87.397,-15.403 -87.6981,-11.4144 -85.6772,-11.3837 -85.6748,-15.3837 -84.5872,-11.383 -84.5848,-15.383 -85.6748,-15.3837 -85.6772,-11.3837 -84.5872,-11.383 -84.5848,-15.383 -84.5272,-11.383 -84.5248,-15.383 -84.5848,-15.383 -84.5872,-11.383 -84.5272,-11.383 -93.7042,-24.7786 -93.704,-23.7786 -93.704,-23.7786 -93.7042,-24.7786 -93.7042,-24.7786 -93.704,-23.7786 -93.704,-23.7786 -93.7038,-22.5909 -93.7038,-22.5909 -93.704,-23.7786 -93.704,-23.7786 -93.7038,-22.5909 -93.7038,-22.5909 -93.6298,-21.5396 -93.6298,-21.5396 -93.7038,-22.5909 -93.7038,-22.5909 -93.6298,-21.5396 -93.6298,-21.5396 -93.4099,-20.5088 -93.4099,-20.5088 -93.6298,-21.5396 -93.6298,-21.5396 -93.4099,-20.5088 -93.4099,-20.5088 -93.0482,-19.5189 -93.0482,-19.5189 -93.4099,-20.5088 -93.4099,-20.5088 -93.0482,-19.5189 -93.0482,-19.5189 -92.552,-18.5891 -92.552,-18.5891 -93.0482,-19.5189 -93.0482,-19.5189 -92.552,-18.5891 -92.552,-18.5891 -91.9309,-17.7376 -91.9309,-17.7376 -92.552,-18.5891 -92.552,-18.5891 -91.9309,-17.7376 -91.9309,-17.7376 -91.196,-16.9885 -91.196,-16.9885 -91.9309,-17.7376 -91.9309,-17.7376 -91.196,-16.9885 -91.196,-16.9885 -90.3543,-16.3679 -90.3543,-16.3679 -91.196,-16.9885 -91.196,-16.9885 -90.3543,-16.3679 -90.3543,-16.3679 -89.4244,-15.8892 -89.4244,-15.8892 -90.3543,-16.3679 -90.3543,-16.3679 -89.4244,-15.8892 -89.4244,-15.8892 -88.4302,-15.5649 -88.4302,-15.5649 -89.4244,-15.8892 -89.4244,-15.8892 -88.4302,-15.5649 -88.4302,-15.5649 -87.397,-15.403 -87.397,-15.403 -88.4302,-15.5649 -88.4302,-15.5649 -87.397,-15.403 -87.397,-15.403 -85.6748,-15.3837 -85.6748,-15.3837 -87.397,-15.403 -87.397,-15.403 -85.6748,-15.3837 -85.6748,-15.3837 -84.5848,-15.383 -84.5848,-15.383 -85.6748,-15.3837 -85.6748,-15.3837 -84.5848,-15.383 -84.5848,-15.383 -84.5248,-15.383 -84.5248,-15.383 -84.5848,-15.383 -84.5848,-15.383 -84.5248,-15.383 --45.2972,29.695 -25.181,25.6627 -25.1828,29.6627 --45.2972,29.695 --45.299,25.695 -25.181,25.6627 --45.2971,29.995 -25.1828,29.6627 -25.1829,29.9627 --45.2971,29.995 --45.2972,29.695 -25.1828,29.6627 --45.2952,33.995 -25.1829,29.9627 -25.1848,33.9627 --45.2952,33.995 --45.2971,29.995 -25.1829,29.9627 --45.2952,33.995 -25.1848,33.9627 -25.1848,33.9627 --45.2952,33.995 --45.2952,33.995 -25.1848,33.9627 --45.2952,33.995 -25.1848,33.9627 -25.1866,37.9627 --45.2952,33.995 -25.1866,37.9627 --45.2934,37.995 --45.2934,37.995 -25.1866,37.9627 -25.1867,38.2627 --45.2934,37.995 -25.1867,38.2627 --45.2932,38.295 --45.2932,38.295 -25.1867,38.2627 -25.1886,42.2627 --45.2932,38.295 -25.1886,42.2627 --45.2914,42.295 -93.7042,-24.7786 -93.704,-23.7783 -93.704,-23.7783 -93.7042,-24.7786 -93.7042,-24.7786 -93.704,-23.7783 -93.704,-23.7783 -93.7003,-22.7696 -93.7003,-22.7696 -93.704,-23.7783 -93.704,-23.7783 -93.7003,-22.7696 -93.7003,-22.7696 -93.6043,-21.7648 -93.6043,-21.7648 -93.7003,-22.7696 -93.7003,-22.7696 -93.6043,-21.7648 -93.6043,-21.7648 -93.3789,-20.781 -93.3789,-20.781 -93.6043,-21.7648 -93.6043,-21.7648 -93.3789,-20.781 -93.3789,-20.781 -93.0279,-19.8347 -93.0279,-19.8347 -93.3789,-20.781 -93.3789,-20.781 -93.0279,-19.8347 -93.0279,-19.8347 -92.5571,-18.9418 -92.5571,-18.9418 -93.0279,-19.8347 -93.0279,-19.8347 -92.5571,-18.9418 -92.5571,-18.9418 -91.9746,-18.1176 -91.9746,-18.1176 -92.5571,-18.9418 -92.5571,-18.9418 -91.9746,-18.1176 -91.9746,-18.1176 -91.2941,-17.3804 -91.2941,-17.3804 -91.9746,-18.1176 -91.9746,-18.1176 -91.2941,-17.3804 -91.2941,-17.3804 -90.5069,-16.7329 -90.5069,-16.7329 -91.2941,-17.3804 -91.2941,-17.3804 -90.5069,-16.7329 -90.5069,-16.7329 -89.6369,-16.2017 -89.6369,-16.2017 -90.5069,-16.7329 -90.5069,-16.7329 -89.6369,-16.2017 -89.6369,-16.2017 -88.7014,-15.797 -88.7014,-15.797 -89.6369,-16.2017 -89.6369,-16.2017 -88.7014,-15.797 -88.7014,-15.797 -87.7185,-15.5268 -87.7185,-15.5268 -88.7014,-15.797 -88.7014,-15.797 -87.7185,-15.5268 -87.7185,-15.5268 -86.7076,-15.3964 -86.7076,-15.3964 -87.7185,-15.5268 -87.7185,-15.5268 -86.7076,-15.3964 -86.7076,-15.3964 -85.6748,-15.3837 -85.6748,-15.3837 -86.7076,-15.3964 -86.7076,-15.3964 -85.6748,-15.3837 -85.6748,-15.3837 -84.5848,-15.383 -84.5848,-15.383 -85.6748,-15.3837 -85.6748,-15.3837 -84.5848,-15.383 -84.5848,-15.383 -84.5248,-15.383 -84.5248,-15.383 -84.5848,-15.383 -84.5848,-15.383 -84.5248,-15.383 -93.7042,-24.7786 -93.704,-23.7783 -89.704,-23.7792 -93.7042,-24.7786 -89.704,-23.7792 -89.7042,-24.7795 -93.704,-23.7783 -93.7003,-22.7696 -89.7021,-22.8905 -93.704,-23.7783 -89.7021,-22.8905 -89.704,-23.7792 -93.7003,-22.7696 -93.6043,-21.7648 -89.6556,-22.403 -93.7003,-22.7696 -89.6556,-22.403 -89.7021,-22.8905 -93.6043,-21.7648 -93.3789,-20.781 -89.5462,-21.9257 -93.6043,-21.7648 -89.5462,-21.9257 -89.6556,-22.403 -93.3789,-20.781 -93.0279,-19.8347 -89.3759,-21.4665 -93.3789,-20.781 -89.3759,-21.4665 -89.5462,-21.9257 -93.0279,-19.8347 -92.5571,-18.9418 -89.1475,-21.0333 -93.0279,-19.8347 -89.1475,-21.0333 -89.3759,-21.4665 -92.5571,-18.9418 -91.9746,-18.1176 -88.8648,-20.6334 -92.5571,-18.9418 -88.8648,-20.6334 -89.1475,-21.0333 -91.9746,-18.1176 -91.2941,-17.3804 -88.5435,-20.2845 -91.9746,-18.1176 -88.5435,-20.2845 -88.8648,-20.6334 -91.2941,-17.3804 -90.5069,-16.7329 -88.1884,-19.9925 -91.2941,-17.3804 -88.1884,-19.9925 -88.5435,-20.2845 -90.5069,-16.7329 -89.6369,-16.2017 -87.796,-19.7529 -90.5069,-16.7329 -87.796,-19.7529 -88.1884,-19.9925 -89.6369,-16.2017 -88.7014,-15.797 -87.374,-19.5703 -89.6369,-16.2017 -87.374,-19.5703 -87.796,-19.7529 -88.7014,-15.797 -87.7185,-15.5268 -86.9307,-19.4485 -88.7014,-15.797 -86.9307,-19.4485 -87.374,-19.5703 -87.7185,-15.5268 -86.7076,-15.3964 -86.4747,-19.3896 -87.7185,-15.5268 -86.4747,-19.3896 -86.9307,-19.4485 -86.7076,-15.3964 -85.6748,-15.3837 -85.6724,-19.3837 -86.7076,-15.3964 -85.6724,-19.3837 -86.4747,-19.3896 -85.6748,-15.3837 -84.5848,-15.383 -84.5824,-19.383 -85.6748,-15.3837 -84.5824,-19.383 -85.6724,-19.3837 -84.5848,-15.383 -84.5248,-15.383 -84.5224,-19.383 -84.5848,-15.383 -84.5224,-19.383 -84.5824,-19.383 -47.1028,29.6526 -84.541,25.6355 -84.5428,29.6355 -47.1028,29.6526 -47.101,25.6526 -84.541,25.6355 -47.1029,29.9526 -84.5428,29.6355 -84.5429,29.9355 -47.1029,29.9526 -47.1028,29.6526 -84.5428,29.6355 -47.1048,33.9526 -84.5429,29.9355 -84.5448,33.9355 -47.1048,33.9526 -47.1029,29.9526 -84.5429,29.9355 -47.1048,33.9526 -84.5448,33.9355 -84.5448,33.9355 -47.1048,33.9526 -47.1048,33.9526 -84.5448,33.9355 -47.1048,33.9526 -84.5448,33.9355 -84.5466,37.9355 -47.1048,33.9526 -84.5466,37.9355 -47.1066,37.9526 -47.1066,37.9526 -84.5466,37.9355 -84.5467,38.2355 -47.1066,37.9526 -84.5467,38.2355 -47.1067,38.2526 -47.1067,38.2526 -84.5467,38.2355 -84.5486,42.2355 -47.1067,38.2526 -84.5486,42.2355 -47.1086,42.2526 -85.4002,-6.78049 -85.4038,-6.75069 -85.4038,-6.75069 -85.4002,-6.78049 -85.4002,-6.78049 -85.4038,-6.75069 -85.4038,-6.75069 -85.4143,-6.72261 -85.4143,-6.72261 -85.4038,-6.75069 -85.4038,-6.75069 -85.4143,-6.72261 -85.4143,-6.72261 -85.4313,-6.69784 -85.4313,-6.69784 -85.4143,-6.72261 -85.4143,-6.72261 -85.4313,-6.69784 -85.4313,-6.69784 -85.2641,-6.8325 -85.2641,-6.8325 -85.4313,-6.69784 -85.4313,-6.69784 -85.2641,-6.8325 -85.2641,-6.8325 -85.0717,-6.95395 -85.0717,-6.95395 -85.2641,-6.8325 -85.2641,-6.8325 -85.0717,-6.95395 -85.0717,-6.95395 -84.8599,-7.0369 -84.8599,-7.0369 -85.0717,-6.95395 -85.0717,-6.95395 -84.8599,-7.0369 -84.8599,-7.0369 -84.6362,-7.07834 -84.6362,-7.07834 -84.8599,-7.0369 -84.8599,-7.0369 -84.6362,-7.07834 -84.6362,-7.07834 -84.5299,-7.083 -84.5299,-7.083 -84.6362,-7.07834 -84.6362,-7.07834 -84.5299,-7.083 -85.4002,-6.78049 -85.4038,-6.75069 -89.2893,-7.70063 -85.4002,-6.78049 -89.2893,-7.70063 -89.4002,-6.77958 -85.4038,-6.75069 -85.4143,-6.72261 -88.9627,-8.56892 -85.4038,-6.75069 -88.9627,-8.56892 -89.2893,-7.70063 -85.4143,-6.72261 -85.4313,-6.69784 -88.4391,-9.3347 -85.4143,-6.72261 -88.4391,-9.3347 -88.9627,-8.56892 -85.4313,-6.69784 -85.2641,-6.8325 -87.7108,-9.99686 -85.4313,-6.69784 -87.7108,-9.99686 -88.4391,-9.3347 -85.2641,-6.8325 -85.0717,-6.95395 -86.8768,-10.5235 -85.2641,-6.8325 -86.8768,-10.5235 -87.7108,-9.99686 -85.0717,-6.95395 -84.8599,-7.0369 -85.9584,-10.8831 -85.0717,-6.95395 -85.9584,-10.8831 -86.8768,-10.5235 -84.8599,-7.0369 -84.6362,-7.07834 -84.9885,-11.0628 -84.8599,-7.0369 -84.9885,-11.0628 -85.9584,-10.8831 -84.6362,-7.07834 -84.5299,-7.083 -84.5276,-11.083 -84.6362,-7.07834 -84.5276,-11.083 -84.9885,-11.0628 -89.4002,-6.77958 -89.2893,-7.70063 -89.5807,-7.77187 -89.4002,-6.77958 -89.5807,-7.77187 -89.7002,-6.77951 -89.2893,-7.70063 -88.9627,-8.56892 -89.2289,-8.7074 -89.2893,-7.70063 -89.2289,-8.7074 -89.5807,-7.77187 -88.9627,-8.56892 -88.4391,-9.3347 -88.6647,-9.53246 -88.9627,-8.56892 -88.6647,-9.53246 -89.2289,-8.7074 -88.4391,-9.3347 -87.7108,-9.99686 -87.8944,-10.2342 -88.4391,-9.3347 -87.8944,-10.2342 -88.6647,-9.53246 -87.7108,-9.99686 -86.8768,-10.5235 -87.0122,-10.7912 -87.7108,-9.99686 -87.0122,-10.7912 -87.8944,-10.2342 -86.8768,-10.5235 -85.9584,-10.8831 -86.0408,-11.1716 -86.8768,-10.5235 -86.0408,-11.1716 -87.0122,-10.7912 -85.9584,-10.8831 -84.9885,-11.0628 -85.015,-11.3616 -85.9584,-10.8831 -85.015,-11.3616 -86.0408,-11.1716 -84.9885,-11.0628 -84.5276,-11.083 -84.5274,-11.383 -84.9885,-11.0628 -84.5274,-11.383 -85.015,-11.3616 -93.7002,-6.77861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7002,-6.77861 -93.7002,-6.77861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7007,-9.02887 -93.7007,-9.02887 -93.7004,-7.92861 -93.7004,-7.92861 -93.7007,-9.02887 -93.7007,-9.02887 -93.6137,-10.0523 -93.6137,-10.0523 -93.7007,-9.02887 -93.7007,-9.02887 -93.6137,-10.0523 -93.6137,-10.0523 -93.3548,-11.0463 -93.3548,-11.0463 -93.6137,-10.0523 -93.6137,-10.0523 -93.3548,-11.0463 -93.3548,-11.0463 -92.9314,-11.9821 -92.9314,-11.9821 -93.3548,-11.0463 -93.3548,-11.0463 -92.9314,-11.9821 -92.9314,-11.9821 -92.3559,-12.8328 -92.3559,-12.8328 -92.9314,-11.9821 -92.9314,-11.9821 -92.3559,-12.8328 -92.3559,-12.8328 -91.6202,-13.5965 -91.6202,-13.5965 -92.3559,-12.8328 -92.3559,-12.8328 -91.6202,-13.5965 -91.6202,-13.5965 -90.7748,-14.2404 -90.7748,-14.2404 -91.6202,-13.5965 -91.6202,-13.5965 -90.7748,-14.2404 -90.7748,-14.2404 -89.8427,-14.7508 -89.8427,-14.7508 -90.7748,-14.2404 -90.7748,-14.2404 -89.8427,-14.7508 -89.8427,-14.7508 -88.8448,-15.1162 -88.8448,-15.1162 -89.8427,-14.7508 -89.8427,-14.7508 -88.8448,-15.1162 -88.8448,-15.1162 -87.8034,-15.3283 -87.8034,-15.3283 -88.8448,-15.1162 -88.8448,-15.1162 -87.8034,-15.3283 -87.8034,-15.3283 -85.4348,-15.3836 -85.4348,-15.3836 -87.8034,-15.3283 -87.8034,-15.3283 -85.4348,-15.3836 -85.4348,-15.3836 -84.5248,-15.383 -84.5248,-15.383 -85.4348,-15.3836 -85.4348,-15.3836 -84.5248,-15.383 -93.7002,-6.77861 -93.7004,-7.92861 -97.7004,-7.92771 -93.7002,-6.77861 -97.7004,-7.92771 -97.7002,-6.77771 -93.7004,-7.92861 -93.7007,-9.02887 -97.7007,-9.02814 -93.7004,-7.92861 -97.7007,-9.02814 -97.7004,-7.92771 -93.7007,-9.02887 -93.6137,-10.0523 -97.5561,-10.7283 -93.7007,-9.02887 -97.5561,-10.7283 -97.7007,-9.02814 -93.6137,-10.0523 -93.3548,-11.0463 -97.126,-12.3795 -93.6137,-10.0523 -97.126,-12.3795 -97.5561,-10.7283 -93.3548,-11.0463 -92.9314,-11.9821 -96.4228,-13.9342 -93.3548,-11.0463 -96.4228,-13.9342 -97.126,-12.3795 -92.9314,-11.9821 -92.3559,-12.8328 -95.4666,-15.3474 -92.9314,-11.9821 -95.4666,-15.3474 -96.4228,-13.9342 -92.3559,-12.8328 -91.6202,-13.5965 -94.2756,-16.5879 -92.3559,-12.8328 -94.2756,-16.5879 -95.4666,-15.3474 -91.6202,-13.5965 -90.7748,-14.2404 -92.9534,-17.5951 -91.6202,-13.5965 -92.9534,-17.5951 -94.2756,-16.5879 -90.7748,-14.2404 -89.8427,-14.7508 -91.4955,-18.3934 -90.7748,-14.2404 -91.4955,-18.3934 -92.9534,-17.5951 -89.8427,-14.7508 -88.8448,-15.1162 -89.9346,-18.9648 -89.8427,-14.7508 -89.9346,-18.9648 -91.4955,-18.3934 -88.8448,-15.1162 -87.8034,-15.3283 -88.3059,-19.2966 -88.8448,-15.1162 -88.3059,-19.2966 -89.9346,-18.9648 -87.8034,-15.3283 -85.4348,-15.3836 -85.4324,-19.3836 -87.8034,-15.3283 -85.4324,-19.3836 -88.3059,-19.2966 -85.4348,-15.3836 -84.5248,-15.383 -84.5224,-19.383 -85.4348,-15.3836 -84.5224,-19.383 -85.4324,-19.3836 -84.5248,-15.383 -85.6748,-15.3837 -85.6748,-15.3837 -84.5248,-15.383 -84.5248,-15.383 -85.6748,-15.3837 -85.6748,-15.3837 -86.7914,-15.3844 -86.7914,-15.3844 -85.6748,-15.3837 -85.6748,-15.3837 -86.7914,-15.3844 -86.7914,-15.3844 -87.8187,-15.313 -87.8187,-15.313 -86.7914,-15.3844 -86.7914,-15.3844 -87.8187,-15.313 -87.8187,-15.313 -88.826,-15.0989 -88.826,-15.0989 -87.8187,-15.313 -87.8187,-15.313 -88.826,-15.0989 -88.826,-15.0989 -89.7936,-14.7464 -89.7936,-14.7464 -88.826,-15.0989 -88.826,-15.0989 -89.7936,-14.7464 -89.7936,-14.7464 -90.6861,-14.2725 -90.6861,-14.2725 -89.7936,-14.7464 -89.7936,-14.7464 -90.6861,-14.2725 -90.6861,-14.2725 -91.5349,-13.6561 -91.5349,-13.6561 -90.6861,-14.2725 -90.6861,-14.2725 -91.5349,-13.6561 -91.5349,-13.6561 -92.2593,-12.9385 -92.2593,-12.9385 -91.5349,-13.6561 -91.5349,-13.6561 -92.2593,-12.9385 -92.2593,-12.9385 -92.8553,-12.1049 -92.8553,-12.1049 -92.2593,-12.9385 -92.2593,-12.9385 -92.8553,-12.1049 -92.8553,-12.1049 -93.3016,-11.1826 -93.3016,-11.1826 -92.8553,-12.1049 -92.8553,-12.1049 -93.3016,-11.1826 -93.3016,-11.1826 -93.5855,-10.198 -93.5855,-10.198 -93.3016,-11.1826 -93.3016,-11.1826 -93.5855,-10.198 -93.5855,-10.198 -93.6987,-9.17955 -93.6987,-9.17955 -93.5855,-10.198 -93.5855,-10.198 -93.6987,-9.17955 -93.6987,-9.17955 -93.7004,-7.92861 -93.7004,-7.92861 -93.6987,-9.17955 -93.6987,-9.17955 -93.7004,-7.92861 -93.7004,-7.92861 -93.7002,-6.77861 -93.7002,-6.77861 -93.7004,-7.92861 -93.7004,-7.92861 -93.7002,-6.77861 -84.5248,-15.383 -85.6748,-15.3837 -85.6772,-11.3837 -84.5248,-15.383 -85.6772,-11.3837 -84.5272,-11.383 -85.6748,-15.3837 -86.7914,-15.3844 -86.7938,-11.3844 -85.6748,-15.3837 -86.7938,-11.3844 -85.6772,-11.3837 -86.7914,-15.3844 -87.8187,-15.313 -87.2629,-11.3518 -86.7914,-15.3844 -87.2629,-11.3518 -86.7938,-11.3844 -87.8187,-15.313 -88.826,-15.0989 -87.7229,-11.254 -87.8187,-15.313 -87.7229,-11.254 -87.2629,-11.3518 -88.826,-15.0989 -89.7936,-14.7464 -88.1647,-11.093 -88.826,-15.0989 -88.1647,-11.093 -87.7229,-11.254 -89.7936,-14.7464 -90.6861,-14.2725 -88.5723,-10.8766 -89.7936,-14.7464 -88.5723,-10.8766 -88.1647,-11.093 -90.6861,-14.2725 -91.5349,-13.6561 -88.9599,-10.5952 -90.6861,-14.2725 -88.9599,-10.5952 -88.5723,-10.8766 -91.5349,-13.6561 -92.2593,-12.9385 -89.2147,-10.3442 -91.5349,-13.6561 -89.2147,-10.3442 -88.9599,-10.5952 -92.2593,-12.9385 -92.8553,-12.1049 -89.4156,-10.0632 -92.2593,-12.9385 -89.4156,-10.0632 -89.2147,-10.3442 -92.8553,-12.1049 -93.3016,-11.1826 -89.5661,-9.75215 -92.8553,-12.1049 -89.5661,-9.75215 -89.4156,-10.0632 -93.3016,-11.1826 -93.5855,-10.198 -89.6618,-9.42015 -93.3016,-11.1826 -89.6618,-9.42015 -89.5661,-9.75215 -93.5855,-10.198 -93.6987,-9.17955 -89.7,-9.07675 -93.5855,-10.198 -89.7,-9.07675 -89.6618,-9.42015 -93.6987,-9.17955 -93.7004,-7.92861 -89.7004,-7.92951 -93.6987,-9.17955 -89.7004,-7.92951 -89.7,-9.07675 -93.7004,-7.92861 -93.7002,-6.77861 -89.7002,-6.77951 -93.7004,-7.92861 -89.7002,-6.77951 -89.7004,-7.92951 --49.836,-72.3882 --45.8401,-24.3279 --49.8401,-24.3282 --49.836,-72.3882 --45.836,-72.3879 --45.8401,-24.3279 --50.136,-72.3883 --49.8401,-24.3282 --50.1401,-24.3283 --50.136,-72.3883 --49.836,-72.3882 --49.8401,-24.3282 --54.136,-72.3886 --50.1401,-24.3283 --54.1401,-24.3286 --54.136,-72.3886 --50.136,-72.3883 --50.1401,-24.3283 --54.136,-72.3886 --54.1401,-24.3286 --54.1401,-24.3286 --54.136,-72.3886 --54.136,-72.3886 --54.1401,-24.3286 --54.136,-72.3886 --54.1401,-24.3286 --58.1401,-24.329 --54.136,-72.3886 --58.1401,-24.329 --58.136,-72.389 --58.136,-72.389 --58.1401,-24.329 --58.4401,-24.329 --58.136,-72.389 --58.4401,-24.329 --58.436,-72.389 --58.436,-72.389 --58.4401,-24.329 --62.4401,-24.3293 --58.436,-72.389 --62.4401,-24.3293 --62.436,-72.3893 --49.8419,-4.01825 --45.8444,24.3621 --49.8444,24.3618 --49.8419,-4.01825 --45.8419,-4.0179 --45.8444,24.3621 --50.1419,-4.01827 --49.8444,24.3618 --50.1444,24.3617 --50.1419,-4.01827 --49.8419,-4.01825 --49.8444,24.3618 --54.1419,-4.01862 --50.1444,24.3617 --54.1444,24.3614 --54.1419,-4.01862 --50.1419,-4.01827 --50.1444,24.3617 --54.1419,-4.01862 --54.1444,24.3614 --54.1444,24.3614 --54.1419,-4.01862 --54.1419,-4.01862 --54.1444,24.3614 --54.1419,-4.01862 --54.1444,24.3614 --58.1444,24.361 --54.1419,-4.01862 --58.1444,24.361 --58.1419,-4.01897 --58.1419,-4.01897 --58.1444,24.361 --58.4444,24.361 --58.1419,-4.01897 --58.4444,24.361 --58.4419,-4.01899 --58.4419,-4.01899 --58.4444,24.361 --62.4444,24.3607 --58.4419,-4.01899 --62.4444,24.3607 --62.4419,-4.01934 -40.4237,-6.61297 -44.4551,24.403 -40.4551,24.407 -40.4237,-6.61297 -44.4237,-6.61702 -44.4551,24.403 -40.1237,-6.61266 -40.4551,24.407 -40.1551,24.4073 -40.1237,-6.61266 -40.4237,-6.61297 -40.4551,24.407 -36.1237,-6.60861 -40.1551,24.4073 -36.1551,24.4114 -36.1237,-6.60861 -40.1237,-6.61266 -40.1551,24.4073 -36.1237,-6.60861 -36.1551,24.4114 -36.1551,24.4114 -36.1237,-6.60861 -36.1237,-6.60861 -36.1551,24.4114 -36.1237,-6.60861 -36.1551,24.4114 -32.1551,24.4154 -36.1237,-6.60861 -32.1551,24.4154 -32.1237,-6.60456 -32.1237,-6.60456 -32.1551,24.4154 -31.8551,24.4157 -32.1237,-6.60456 -31.8551,24.4157 -31.8237,-6.60425 -31.8237,-6.60425 -31.8551,24.4157 -27.8551,24.4198 -31.8237,-6.60425 -27.8551,24.4198 -27.8237,-6.6002 --54.1401,-24.3286 --54.1402,-23.2086 --54.1402,-23.2086 --54.1401,-24.3286 --54.1401,-24.3286 --54.1402,-23.2086 --54.1402,-23.2086 --54.1409,-15.0586 --54.1409,-15.0586 --54.1402,-23.2086 --54.1402,-23.2086 --54.1409,-15.0586 --54.1409,-15.0586 --54.1415,-8.49862 --54.1415,-8.49862 --54.1409,-15.0586 --54.1409,-15.0586 --54.1415,-8.49862 --54.1415,-8.49862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1415,-8.49862 --54.1415,-8.49862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1419,-4.01862 --54.1419,-4.01862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1419,-4.01862 --54.1401,-24.3286 --54.1402,-23.2086 --58.1402,-23.209 --54.1401,-24.3286 --58.1402,-23.209 --58.1401,-24.329 --54.1402,-23.2086 --54.1409,-15.0586 --58.1409,-15.059 --54.1402,-23.2086 --58.1409,-15.059 --58.1402,-23.209 --54.1409,-15.0586 --54.1415,-8.49862 --58.1415,-8.49897 --54.1409,-15.0586 --58.1415,-8.49897 --58.1409,-15.059 --54.1415,-8.49862 --54.1417,-6.32862 --58.1417,-6.32897 --54.1415,-8.49862 --58.1417,-6.32897 --58.1415,-8.49897 --54.1417,-6.32862 --54.1419,-4.01862 --58.1419,-4.01897 --54.1417,-6.32862 --58.1419,-4.01897 --58.1417,-6.32897 --58.1401,-24.329 --58.1402,-23.209 --58.4402,-23.209 --58.1401,-24.329 --58.4402,-23.209 --58.4401,-24.329 --58.1402,-23.209 --58.1409,-15.059 --58.4409,-15.059 --58.1402,-23.209 --58.4409,-15.059 --58.4402,-23.209 --58.1409,-15.059 --58.1415,-8.49897 --58.4415,-8.49899 --58.1409,-15.059 --58.4415,-8.49899 --58.4409,-15.059 --58.1415,-8.49897 --58.1417,-6.32897 --58.4417,-6.32899 --58.1415,-8.49897 --58.4417,-6.32899 --58.4415,-8.49899 --58.1417,-6.32897 --58.1419,-4.01897 --58.4419,-4.01899 --58.1417,-6.32897 --58.4419,-4.01899 --58.4417,-6.32899 --58.4401,-24.329 --58.4402,-23.209 --62.4402,-23.2093 --58.4401,-24.329 --62.4402,-23.2093 --62.4401,-24.3293 --58.4402,-23.209 --58.4409,-15.059 --62.4409,-15.0593 --58.4402,-23.209 --62.4409,-15.0593 --62.4402,-23.2093 --58.4409,-15.059 --58.4415,-8.49899 --62.4415,-8.49934 --58.4409,-15.059 --62.4415,-8.49934 --62.4409,-15.0593 --58.4415,-8.49899 --58.4417,-6.32899 --62.4417,-6.32934 --58.4415,-8.49899 --62.4417,-6.32934 --62.4415,-8.49934 --58.4417,-6.32899 --58.4419,-4.01899 --62.4419,-4.01934 --58.4417,-6.32899 --62.4419,-4.01934 --62.4417,-6.32934 --54.1401,-24.3286 --50.1402,-23.2083 --54.1402,-23.2086 --54.1401,-24.3286 --50.1401,-24.3283 --50.1402,-23.2083 --54.1402,-23.2086 --50.1409,-15.0583 --54.1409,-15.0586 --54.1402,-23.2086 --50.1402,-23.2083 --50.1409,-15.0583 --54.1409,-15.0586 --50.1415,-8.49827 --54.1415,-8.49862 --54.1409,-15.0586 --50.1409,-15.0583 --50.1415,-8.49827 --54.1415,-8.49862 --50.1417,-6.32827 --54.1417,-6.32862 --54.1415,-8.49862 --50.1415,-8.49827 --50.1417,-6.32827 --54.1417,-6.32862 --50.1419,-4.01827 --54.1419,-4.01862 --54.1417,-6.32862 --50.1417,-6.32827 --50.1419,-4.01827 --54.1401,-24.3286 --54.1402,-23.2086 --54.1402,-23.2086 --54.1401,-24.3286 --54.1401,-24.3286 --54.1402,-23.2086 --54.1402,-23.2086 --54.1409,-15.0586 --54.1409,-15.0586 --54.1402,-23.2086 --54.1402,-23.2086 --54.1409,-15.0586 --54.1409,-15.0586 --54.1415,-8.49862 --54.1415,-8.49862 --54.1409,-15.0586 --54.1409,-15.0586 --54.1415,-8.49862 --54.1415,-8.49862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1415,-8.49862 --54.1415,-8.49862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1419,-4.01862 --54.1419,-4.01862 --54.1417,-6.32862 --54.1417,-6.32862 --54.1419,-4.01862 --43.2752,-15.3054 --45.2728,-11.3042 --45.2752,-15.3042 --43.2752,-15.3054 --43.2728,-11.3054 --45.2728,-11.3042 --45.2752,-15.3042 --47.4084,-11.3029 --47.4108,-15.3029 --45.2752,-15.3042 --45.2728,-11.3042 --47.4084,-11.3029 --47.4108,-15.3029 --49.0428,-11.4247 --48.4474,-15.3801 --47.4108,-15.3029 --47.4084,-11.3029 --49.0428,-11.4247 --48.4474,-15.3801 --50.6406,-11.7894 --49.4608,-15.6114 --48.4474,-15.3801 --49.0428,-11.4247 --50.6406,-11.7894 --49.4608,-15.6114 --52.166,-12.3887 --50.4283,-15.9916 --49.4608,-15.6114 --50.6406,-11.7894 --52.166,-12.3887 --50.4283,-15.9916 --53.5846,-13.2093 --51.3281,-16.512 --50.4283,-15.9916 --52.166,-12.3887 --53.5846,-13.2093 --51.3281,-16.512 --54.8648,-14.2327 --52.14,-17.1611 --51.3281,-16.512 --53.5846,-13.2093 --54.8648,-14.2327 --52.14,-17.1611 --55.9756,-15.4462 --52.8184,-17.9022 --52.14,-17.1611 --54.8648,-14.2327 --55.9756,-15.4462 --52.8184,-17.9022 --56.8771,-16.8187 --53.3689,-18.7404 --52.8184,-17.9022 --55.9756,-15.4462 --56.8771,-16.8187 --53.3689,-18.7404 --57.5484,-18.3174 --53.7788,-19.6556 --53.3689,-18.7404 --56.8771,-16.8187 --57.5484,-18.3174 --53.7788,-19.6556 --57.9723,-19.9038 --54.0377,-20.6244 --53.7788,-19.6556 --57.5484,-18.3174 --57.9723,-19.9038 --54.0377,-20.6244 --58.1381,-21.5375 --54.139,-21.622 --54.0377,-20.6244 --57.9723,-19.9038 --58.1381,-21.5375 --54.139,-21.622 --58.1403,-22.799 --54.1403,-22.7986 --54.139,-21.622 --58.1381,-21.5375 --58.1403,-22.799 --54.1403,-22.7986 --58.1401,-24.329 --54.1401,-24.3286 --54.1403,-22.7986 --58.1403,-22.799 --58.1401,-24.329 --43.2752,-15.3054 --45.2752,-15.3042 --45.2752,-15.3042 --43.2752,-15.3054 --43.2752,-15.3054 --45.2752,-15.3042 --45.2752,-15.3042 --47.4108,-15.3029 --47.4108,-15.3029 --45.2752,-15.3042 --45.2752,-15.3042 --47.4108,-15.3029 --47.4108,-15.3029 --48.4474,-15.3801 --48.4474,-15.3801 --47.4108,-15.3029 --47.4108,-15.3029 --48.4474,-15.3801 --48.4474,-15.3801 --49.4608,-15.6114 --49.4608,-15.6114 --48.4474,-15.3801 --48.4474,-15.3801 --49.4608,-15.6114 --49.4608,-15.6114 --50.4283,-15.9916 --50.4283,-15.9916 --49.4608,-15.6114 --49.4608,-15.6114 --50.4283,-15.9916 --50.4283,-15.9916 --51.3281,-16.512 --51.3281,-16.512 --50.4283,-15.9916 --50.4283,-15.9916 --51.3281,-16.512 --51.3281,-16.512 --52.14,-17.1611 --52.14,-17.1611 --51.3281,-16.512 --51.3281,-16.512 --52.14,-17.1611 --52.14,-17.1611 --52.8184,-17.9022 --52.8184,-17.9022 --52.14,-17.1611 --52.14,-17.1611 --52.8184,-17.9022 --52.8184,-17.9022 --53.3689,-18.7404 --53.3689,-18.7404 --52.8184,-17.9022 --52.8184,-17.9022 --53.3689,-18.7404 --53.3689,-18.7404 --53.7788,-19.6556 --53.7788,-19.6556 --53.3689,-18.7404 --53.3689,-18.7404 --53.7788,-19.6556 --53.7788,-19.6556 --54.0377,-20.6244 --54.0377,-20.6244 --53.7788,-19.6556 --53.7788,-19.6556 --54.0377,-20.6244 --54.0377,-20.6244 --54.139,-21.622 --54.139,-21.622 --54.0377,-20.6244 --54.0377,-20.6244 --54.139,-21.622 --54.139,-21.622 --54.1403,-22.7986 --54.1403,-22.7986 --54.139,-21.622 --54.139,-21.622 --54.1403,-22.7986 --54.1403,-22.7986 --54.1401,-24.3286 --54.1401,-24.3286 --54.1403,-22.7986 --54.1403,-22.7986 --54.1401,-24.3286 diff --git a/result.jpg b/result.jpg deleted file mode 100644 index a33c5d886..000000000 Binary files a/result.jpg and /dev/null differ diff --git a/src/control/carla_controller/carla_controller/simple_route_controller.py b/src/control/carla_controller/carla_controller/simple_route_controller.py index 6d6939a18..f10e0e5a9 100644 --- a/src/control/carla_controller/carla_controller/simple_route_controller.py +++ b/src/control/carla_controller/carla_controller/simple_route_controller.py @@ -7,10 +7,17 @@ ''' from carla_msgs.msg import CarlaEgoVehicleControl +from geometry_msgs.msg import TransformStamped from nav_msgs.msg import Path from rosgraph_msgs.msg import Clock import rclpy from rclpy.node import Node +from tf2_ros import TransformException +from tf2_ros.buffer import Buffer +from tf2_ros.transform_listener import TransformListener + +import numpy as np +import shapely class SimpleRouteControllerNode(Node): @@ -34,11 +41,51 @@ def __init__(self): Path, '/route/smooth_path', self.path_cb, 10) self.path_msg = Path() + # Transform listener + self.tf_buffer = Buffer() + self.tf_listener = TransformListener(self.tf_buffer, self) + + self.path_linestring = None + # self.control_timer = self.create_timer(0.05, self.generate_commands) def path_cb(self, msg: Path): + self.get_logger().info("Received smooth path") self.path_msg = msg + if self.path_linestring is None: + # Construct a shapely LineString + pts = [] + for pose in msg.poses: + pts.append(np.array([pose.pose.position.x, pose.pose.position.y])) + + self.route_pts_arr = np.array(pts) + + print(str(self.route_pts_arr)) + + # Get map->base_link transform + t = TransformStamped() + try: + t = self.tf_buffer.lookup_transform( + 'base_link', + 'map', + rclpy.time.Time()) + except TransformException as ex: + self.get_logger().info( + f'Could not transform from map to base_link: {ex}') + return + + # Transform linestring to base_link + self.route_pts_arr[:,0] += t.transform.translation.x + self.route_pts_arr[:,1] += t.transform.translation.y + + linestring = shapely.LineString(self.route_pts_arr) + current_pos = shapely.Point(0.0, 0.0) # Our vehicle is at the origin of base_link, by definition + + distance = shapely.distance(linestring, current_pos) + self.get_logger().info(str(distance)) + + def generate_commands(self): # Form a blank command message diff --git a/src/control/parade_controller/package.xml b/src/control/parade_controller/package.xml new file mode 100755 index 000000000..3896b2c68 --- /dev/null +++ b/src/control/parade_controller/package.xml @@ -0,0 +1,19 @@ + + + + parade_controller + 1.0.0 + A simple controller that moves the car forward relative to our reflective banner + Daniel Vayman + MIT + + ament_copyright + ament_flake8 + ament_pep257 + carla_msgs + python3-pytest + + + ament_python + + diff --git a/src/mapping/map_management_old/map_management/__init__.py b/src/control/parade_controller/parade_controller/__init__.py similarity index 100% rename from src/mapping/map_management_old/map_management/__init__.py rename to src/control/parade_controller/parade_controller/__init__.py diff --git a/src/control/parade_controller/parade_controller/parade_controller_node.py b/src/control/parade_controller/parade_controller/parade_controller_node.py new file mode 100755 index 000000000..1fe51cde4 --- /dev/null +++ b/src/control/parade_controller/parade_controller/parade_controller_node.py @@ -0,0 +1,180 @@ +''' +Package: parade_controller +Filename: controller.py +Author: Daniel Vayman + +Controller for the hoco parade that follows our flag +''' + +from carla_msgs.msg import CarlaEgoVehicleControl +from geometry_msgs.msg import TransformStamped +from rosgraph_msgs.msg import Clock +from rclpy.node import Node + +from sensor_msgs.msg import PointCloud2 + +from scipy.spatial.transform import Rotation as R + +import rclpy +import ros2_numpy as rnp +import numpy as np +from tf2_ros import TransformException +from tf2_ros.buffer import Buffer +from tf2_ros.transform_listener import TransformListener + + +class ParadeController(Node): + + def __init__(self): + super().__init__('parade_controller_node') + + self.INTENSITY_THRESHOLD = 200 + self.DESIRED_DISTANCE = 3.7 + + # PID control params + self.Kp_Throttle = 1 # Proportional gain + self.Kp_Steer = .3 + + self.tf_buffer = Buffer() + self.tf_listener = TransformListener(self.tf_buffer, self) + + # Subscriber + self.lidar_left_sub = self.create_subscription(PointCloud2, 'velodyne_points', self.pointclouds_cb, 10) + + # TF listener + + # Publisher + self.throttle_pub = self.create_publisher( + CarlaEgoVehicleControl, '/carla/hero/vehicle_control_cmd', 10) + + # Debug publisher + self.transformed_lidar_pub = self.create_publisher(PointCloud2, '/lidar_tfed', 1) + + def pointclouds_cb(self, msg: PointCloud2): + + pcd: np.array = rnp.numpify(msg) + + + + # Removes all points below the intensity threshold + + self.get_logger().info(f"Orig: {pcd.shape}") + pcd = pcd[pcd['intensity'] > self.INTENSITY_THRESHOLD] + self.get_logger().info(f"Now: {pcd.shape}") + + + t = TransformStamped() + + try: + t = self.tf_buffer.lookup_transform( + 'base_link', + msg.header.frame_id, + rclpy.time.Time()) + except TransformException as ex: + self.get_logger().info( + f'Could not transform base_link to {msg.header.frame_id}: {ex}') + return + + t: TransformStamped + q = t.transform.rotation + + r = R.from_quat([q.x, q.y, q.z, q.w]) + + x = pcd['x'] + y = pcd['y'] + z = pcd['z'] + + xyz = np.vstack((x, y, z)).T + + xyz = R.apply(r, xyz) + + pcd['x'] = xyz[:,0] + pcd['y'] = xyz[:,1] + pcd['z'] = xyz[:,2] + + pcd['x'] += t.transform.translation.x + pcd['y'] += t.transform.translation.y + pcd['z'] += t.transform.translation.z + + x = pcd['x'] + y = pcd['y'] + z = pcd['z'] + xy = np.vstack((x, y)).T + + # Finds the center of mass of banner points, resulting in a 1D numpy array (x, y) with the center coordinate of the banner + banner = np.mean(xy[:, :2], axis=0) + + + # Finds the distance to the banner (distance_x) and how far it is to the right or left (distance_y) + distance_x = abs(banner[0]) + distance_y = banner[1] + + # Error + error_x = distance_x - self.DESIRED_DISTANCE + error_y = distance_y + + # Throttle & steering values TODO: integral & derivative terms + throttle = self.Kp_Throttle * error_x + steer = self.Kp_Steer * error_y + + # Set msg fields and publish throttle value + throttle_msg = CarlaEgoVehicleControl() + + if throttle < 0.: + throttle = 0. + + if steer > 1.: + steer = 1. + elif steer < -1.: + steer = -1. + + throttle_msg.throttle = (1. if throttle > 1. else throttle) + throttle_msg.steer = -1.*steer + + + self.get_logger().info("Distance X: " + str(distance_x)) + self.get_logger().info("Distance Y: " + str(distance_y)) + self.get_logger().info("Thr: " + str(throttle)) + + self.throttle_pub.publish(throttle_msg) + + total_length = pcd['x'].shape[0] + + msg_array = np.zeros(total_length, dtype=[ + ('x', np.float32), + ('y', np.float32), + ('z', np.float32), + ('intensity', np.float32) + ]) + + msg_array['x'] = pcd['x'] + msg_array['y'] = pcd['y'] + msg_array['z'] = pcd['z'] + msg_array['intensity'] = pcd['intensity'] + + tfed_msg: PointCloud2 = rnp.msgify(PointCloud2, msg_array) + + tfed_msg.header = msg.header + tfed_msg.header.frame_id = 'base_link' + + self.transformed_lidar_pub.publish(tfed_msg) + + + + +def main(args=None): + rclpy.init(args=args) + + parade_controller_node = ParadeController() + + rclpy.spin(parade_controller_node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + parade_controller_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/interface/linear_actuator/COLCON_IGNORE b/src/control/parade_controller/resource/parade_controller similarity index 100% rename from src/interface/linear_actuator/COLCON_IGNORE rename to src/control/parade_controller/resource/parade_controller diff --git a/src/control/parade_controller/setup.cfg b/src/control/parade_controller/setup.cfg new file mode 100755 index 000000000..9d138780f --- /dev/null +++ b/src/control/parade_controller/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/parade_controller +[install] +install-scripts=$base/lib/parade_controller diff --git a/src/control/parade_controller/setup.py b/src/control/parade_controller/setup.py new file mode 100755 index 000000000..afc7d8052 --- /dev/null +++ b/src/control/parade_controller/setup.py @@ -0,0 +1,26 @@ +from setuptools import setup + +package_name = 'parade_controller' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='root', + maintainer_email='root@todo.todo', + description='TODO: Package description', + license='TODO: License declaration', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'parade_controller_node = parade_controller.parade_controller_node:main' + ], + }, +) diff --git a/src/perception/dynamic_grid/dynamic_grid/__init__.py b/src/interface/camera/camera/__init__.py similarity index 100% rename from src/perception/dynamic_grid/dynamic_grid/__init__.py rename to src/interface/camera/camera/__init__.py diff --git a/src/interface/camera/camera/camera_node.py b/src/interface/camera/camera/camera_node.py new file mode 100644 index 000000000..679f60bc9 --- /dev/null +++ b/src/interface/camera/camera/camera_node.py @@ -0,0 +1,112 @@ +''' +Package: camera +Filename: camera_node.py +Author: Will Heitman (w at heit.mn) + +Connects to USB webcams and publishes their streams to ROS + +Available webcams are listed using \ + +''' + +import cv2 +from cv_bridge import CvBridge +import numpy as np +from rosgraph_msgs.msg import Clock +from sensor_msgs.msg import Image +import time + +import rclpy +from rclpy.node import Node + + +class camera_node(Node): + + def __init__(self): + super().__init__('camera_node') + + self.bridge = CvBridge() + + # Get active UVC cameras + _, working_ports, _ = self.list_ports() + + self.cameras = [] + self.camera_publishers = [] + + # For each working port, check if it's a ZED cam (not a laptop webcam etc) + for port in working_ports: + with open(f'/sys/class/video4linux/video{port}/name') as f: + contents = f.readline() + if contents.find('ZED') >= 0: + camera = cv2.VideoCapture(port) + self.cameras.append(camera) + + camera_pub = self.create_publisher(Image, f'/camera/camera{len(self.camera_publishers)}', 1) + self.camera_publishers.append(camera_pub) + + # Call publishFrames very frequently. + self.capture_timer = self.create_timer(0.01, self.publishFrames) + + def publishFrames(self): + """Iterate through each camera and publish the latest frame + """ + start = time.time() + + for idx, camera in enumerate(self.cameras): + if not camera.isOpened(): + self.get_logger().warn("Camera could not be opened") + ret, frame = camera.read() + + # Crop to left frame only. ZEDs return both camera in stereo by default. + original_width = frame.shape[1] + frame = frame[:,0:int(original_width/2),:] + + msg = self.bridge.cv2_to_imgmsg(frame, encoding="passthrough") + self.camera_publishers[idx].publish(msg) + + def list_ports(self) -> tuple: + """ + Test the ports and returns a tuple with the available ports and the ones that are working. + + Taken from S.O. + + Returns: + tuple: available, working, and broken ports + """ + non_working_ports = [] + dev_port = 0 + working_ports = [] + available_ports = [] + while len(non_working_ports) < 10: # if there are more than 5 non working ports stop the testing. + camera = cv2.VideoCapture(dev_port) + if not camera.isOpened(): + non_working_ports.append(dev_port) + # print("Port %s is not working." %dev_port) + else: + is_reading, img = camera.read() + w = camera.get(3) + h = camera.get(4) + if is_reading: + # print("Port %s is working and reads images (%s x %s)" %(dev_port,h,w)) + working_ports.append(dev_port) + else: + # print("Port %s for camera ( %s x %s) is present but does not reads." %(dev_port,h,w)) + available_ports.append(dev_port) + dev_port +=1 + return available_ports,working_ports,non_working_ports + + def releaseCameras(self): + """Disconnect from all cameras on shutdown. + """ + for camera in self.cameras: + camera.release() + + +def main(args=None): + rclpy.init(args=args) + node = camera_node() + rclpy.spin(node) + + camera_node.releaseCameras() + camera_node.destroy_node() + rclpy.shutdown() diff --git a/src/perception/dynamic_grid/package.xml b/src/interface/camera/package.xml similarity index 77% rename from src/perception/dynamic_grid/package.xml rename to src/interface/camera/package.xml index 691a6cdb9..effe2a4db 100755 --- a/src/perception/dynamic_grid/package.xml +++ b/src/interface/camera/package.xml @@ -1,9 +1,9 @@ - dynamic_grid + camera 1.0.0 - Nodes for processing sensor data: camera images, LiDAR pointclouds, and more. + Tools to connect to USB webcams and publish the streams to ROS Will Heitman MIT diff --git a/src/mapping/lio_sam/COLCON_IGNORE b/src/interface/camera/resource/camera similarity index 100% rename from src/mapping/lio_sam/COLCON_IGNORE rename to src/interface/camera/resource/camera diff --git a/src/interface/camera/setup.cfg b/src/interface/camera/setup.cfg new file mode 100755 index 000000000..19b8cf928 --- /dev/null +++ b/src/interface/camera/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/camera +[install] +install-scripts=$base/lib/camera diff --git a/src/interface/camera/setup.py b/src/interface/camera/setup.py new file mode 100755 index 000000000..42f243c14 --- /dev/null +++ b/src/interface/camera/setup.py @@ -0,0 +1,30 @@ +from setuptools import setup +from glob import glob +import os + +package_name = 'camera' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + (os.path.join('share', package_name), glob('launch/*.launch.py')) + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='main', + maintainer_email='will.heitman@utdallas.edu', + description='See package.xml', + license='See package.xml', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + #'dynamic_grid_node = dynamic_grid.dynamic_grid_node:main', + 'camera_node = camera.camera_node:main', + ], + }, +) diff --git a/src/interface/carla_interface/carla_interface/carla_agent.py b/src/interface/carla_interface/carla_interface/carla_agent.py index 60d194f4d..cd5cf288f 100755 --- a/src/interface/carla_interface/carla_interface/carla_agent.py +++ b/src/interface/carla_interface/carla_interface/carla_agent.py @@ -29,33 +29,19 @@ def sensors(self): base_link_pos = [0.7, 0.0, 0.28] sensors = [ - {'type': 'sensor.camera.rgb', 'id': 'rgb_center', - 'x': base_link_pos[0]+0.15, - 'y': base_link_pos[1]+0.0, - 'z': base_link_pos[2]+1.6, - 'roll': 0.0, 'pitch': 0.0, 'yaw': 0.0, - 'width': 600, 'height': 400, 'fov': 120}, - {'type': 'sensor.camera.rgb', 'id': 'rgb_left', 'x': base_link_pos[0]+0.0, 'y': base_link_pos[1]-0.15, 'z': base_link_pos[2]+1.6, 'roll': 0.0, 'pitch': 0.0, 'yaw': -0.9, - 'width': 600, 'height': 400, 'fov': 120}, + 'width': 1024, 'height': 512, 'fov': 120}, {'type': 'sensor.camera.rgb', 'id': 'rgb_right', 'x': base_link_pos[0]+0.0, 'y': base_link_pos[1]+0.15, 'z': base_link_pos[2]+1.6, 'roll': 0.0, 'pitch': 0.0, 'yaw': 0.9, - 'width': 600, 'height': 400, 'fov': 120}, - - {'type': 'sensor.camera.rgb', 'id': 'rgb_zoom', - 'x': base_link_pos[0]+0.15, - 'y': base_link_pos[1]+0.0, - 'z': base_link_pos[2]+1.6, - 'roll': 0.0, 'pitch': 0.0, 'yaw': 0.0, - 'width': 600, 'height': 400, 'fov': 40}, + 'width': 1024, 'height': 512, 'fov': 120}, {'type': 'sensor.lidar.ray_cast', 'id': 'lidar', 'x': base_link_pos[0]+0.0, @@ -67,7 +53,7 @@ def sensors(self): {'type': 'sensor.other.gnss', 'id': 'gnss', 'x': base_link_pos[0]+0.0, 'y': base_link_pos[1]+0.0, - 'z': base_link_pos[2]+0.0,}, + 'z': base_link_pos[2]+0.0, }, {'type': 'sensor.other.imu', 'id': 'imu', 'x': base_link_pos[0]+0.0, 'y': base_link_pos[1]+0.0, diff --git a/src/interface/carla_interface/carla_interface/liaison_node.py b/src/interface/carla_interface/carla_interface/liaison_node.py old mode 100755 new mode 100644 index ec29671a9..96185a643 --- a/src/interface/carla_interface/carla_interface/liaison_node.py +++ b/src/interface/carla_interface/carla_interface/liaison_node.py @@ -8,9 +8,12 @@ but more functionality will be added in the future. ''' +import os import rclpy +import random from rclpy.node import Node from rclpy.qos import DurabilityPolicy, QoSProfile +import time from carla_msgs.msg import CarlaRoute, CarlaWorldInfo from geometry_msgs.msg import Pose, PoseStamped @@ -38,31 +41,101 @@ def __init__(self): self.wp_marker_pub = self.create_publisher( MarkerArray, '/viz/wayppoints', 10) - self.world_info_sub = self.create_subscription(CarlaWorldInfo, '/carla/world_info', self.world_info_cb, 10) - self.world_info_pub = self.create_publisher(CarlaWorldInfo, '/carla/world_info', 10) + self.world_info_sub = self.create_subscription( + CarlaWorldInfo, '/carla/world_info', self.world_info_cb, 10) + self.world_info_pub = self.create_publisher( + CarlaWorldInfo, '/carla/world_info', 10) - self.route_path_pub = self.create_publisher(Path, '/route/rough_path', 10) + self.route_path_pub = self.create_publisher( + Path, '/route/rough_path', 10) self.route_repub_timer = self.create_timer(1.0, self.publish_route) self.world_info_cached = None - self.world_info_repub_timer = self.create_timer(5.0, self.repub_world_info) - - # self.client = carla.Client('localhost', 2005) - # self.client.set_timeout(60) - # self.world = self.client.get_world() + self.world_info_repub_timer = self.create_timer( + 5.0, self.repub_world_info) - # settings = self.world.get_settings() - # settings.fixed_delta_seconds = 1.0 / 20 - # settings.synchronous_mode = True - # settings.tile_stream_distance = 650 - # settings.actor_active_distance = 650 + self.route = None + self.clock = Clock() - # self.world.apply_settings(settings) + connect_to_carla = True # TODO: Make this a param - # self.get_logger().info("Settings applied!") + if connect_to_carla is False: + return - self.route = None - self.clock = Clock() + self.client = carla.Client( + 'localhost', 2000 + int(os.environ['ROS_DOMAIN_ID'])) + self.client.set_timeout(60) + self.world = self.client.get_world() + blueprint_library = self.world.get_blueprint_library() + + WALKER_COUNT = 0 + CAR_COUNT = 60 + + # Wait for ego to spawn + time.sleep(5.0) + + # Find ego vehicle + actor_list = self.world.get_actors() + self.ego = actor_list.filter("vehicle.tesla.model3")[0] + self.get_logger().info(str(self.ego)) + + self.actor_true_pose_timer = self.create_timer( + 0.1, self.publish_true_pose) + self.true_pose_pub = self.create_publisher( + PoseStamped, '/true_pose', 10) + + # Spawn some cars + car_count = 0 + car_spawns = self.world.get_map().get_spawn_points() + for spawn in car_spawns: + if car_count > CAR_COUNT: + continue + vehicle_bp = random.choice(blueprint_library.filter('vehicle.*.*')) + actor = self.world.try_spawn_actor(vehicle_bp, spawn) + if actor is not None: + actor.set_autopilot(True) + car_count += 1 + + self.get_logger().info(f"Spawned {car_count} cars!") + + # Spawn some walkers (pedestrians) + walker_ai_bp = blueprint_library.filter('controller.ai.walker')[0] + walker_count = 0 + while walker_count < WALKER_COUNT: + if walker_count > 30: + continue + walker_bp = random.choice(blueprint_library.filter('walker.*.*')) + spawn_point = carla.Transform() + spawn_point.location = self.world.get_random_location_from_navigation() + actor = self.world.try_spawn_actor( + walker_bp, spawn_point) + if actor is not None: + ai_controller = self.world.try_spawn_actor( + walker_ai_bp, spawn_point, attach_to=actor) + if ai_controller is not None: + ai_controller.go_to_location( + self.world.get_random_location_from_navigation()) + walker_count += 1 + + def publish_true_pose(self): + carla_tf = self.ego.get_transform() + carla_pos = carla_tf.location + msg = PoseStamped() + msg.pose.position.x = carla_pos.x + msg.pose.position.y = carla_pos.y + msg.pose.position.z = carla_pos.z + msg.header.frame_id = 'map' + msg.header.stamp = self.clock.clock + + self.true_pose_pub.publish(msg) + + def set_all_lights_to_green(self): + actors = self.world.get_actors() + print(actors) + for actor in actors: + if actor.type_id == 'traffic.traffic_light': + actor.set_red_time(1.0) + actor.set_yellow_time(0.5) def world_info_cb(self, msg: CarlaWorldInfo): if msg.opendrive == "": @@ -74,7 +147,6 @@ def repub_world_info(self): return self.world_info_pub.publish(self.world_info_cached) - def clock_cb(self, msg: Clock): self.clock = msg @@ -91,7 +163,7 @@ def publish_route(self): for pose in self.route.poses: pose: Pose - pose.position.z = 0.0 # Ignore height. TODO: Support z != 0. + pose.position.z = 0.0 # Ignore height. TODO: Support z != 0. pose_stamped = PoseStamped() pose_stamped.pose = pose pose_stamped.header.frame_id = 'map' diff --git a/src/interface/carla_interface/carla_interface/route_reader.py b/src/interface/carla_interface/carla_interface/route_reader.py new file mode 100644 index 000000000..197c31c12 --- /dev/null +++ b/src/interface/carla_interface/carla_interface/route_reader.py @@ -0,0 +1,91 @@ +''' +Package: carla +Filename: route_reader.py +Author: Will Heitman (w at heit.mn) + +Reads routes from a CARLA-formatted XML file and +publishes it as a Path message +''' + +import os +import rclpy +import random +from rclpy.node import Node +from rclpy.qos import DurabilityPolicy, QoSProfile +import time +import xml.etree.ElementTree as ET + +from carla_msgs.msg import CarlaRoute, CarlaWorldInfo +from geometry_msgs.msg import Pose, PoseStamped +from nav_msgs.msg import Path +from rosgraph_msgs.msg import Clock +from std_msgs.msg import Bool, ColorRGBA +from visualization_msgs.msg import Marker, MarkerArray + +import carla + + +class RouteReaderNode(Node): + + def __init__(self): + super().__init__('route_reader_node') + self.route_pub = self.create_publisher( + Path, '/planning/rough_route', qos_profile=QoSProfile(depth=1, durability=DurabilityPolicy.TRANSIENT_LOCAL)) + route_timer = self.create_timer(1.0, self.publish_route) + + self.clock_sub = self.create_subscription( + Clock, '/clock', self.clock_cb, 10) + + self.route = None + self.clock = Clock() + + tree = ET.parse('/navigator/data/routes_town02.xml') + + TARGET_ROUTE_ID: str = "0" + + route_elem = None + + for route in tree.getroot(): + if route.attrib['id'] == TARGET_ROUTE_ID: + route_elem = route + + if route_elem is None: + self.get_logger().error("Route not found!") + quit(-1) + + self.route = Path() + self.route.header.frame_id = 'map' + self.route.header.stamp = self.clock.clock + + for position in route_elem.find('waypoints'): + print(position.attrib) + wp = PoseStamped() + wp.header.frame_id = 'map' + wp.header.stamp = self.clock.clock + wp.pose.position.x = float(position.attrib.get('x')) + wp.pose.position.y = float(position.attrib.get('y')) + self.route.poses.append(wp) + + def clock_cb(self, msg: Clock): + self.clock = msg + + def publish_route(self): + self.route_pub.publish(self.route) + + +def main(args=None): + rclpy.init(args=args) + + liaison_node = RouteReaderNode() + + rclpy.spin(liaison_node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + liaison_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/interface/carla_interface/launch/carla.launch.py b/src/interface/carla_interface/launch/carla.launch.py index f20bb7c0c..310a613ab 100644 --- a/src/interface/carla_interface/launch/carla.launch.py +++ b/src/interface/carla_interface/launch/carla.launch.py @@ -48,6 +48,26 @@ def generate_launch_description(): arguments=[path.join("/navigator/data", "carla.urdf")] ) + airbags = Node( + package='airbags', + executable='airbag_node' + ) + + camera_streamer = Node( + package='web_video_server', + executable='web_video_server' + ) + + joy_linux = Node( + package="joy_linux", + executable="joy_linux_node" + ) + + joy_translation = Node( + package="joy_translation", + executable="joy_translation_node" + ) + carla_bridge_official = IncludeLaunchDescription( PythonLaunchDescriptionSource([get_package_share_directory( 'carla_ros_bridge'), '/carla_ros_bridge.launch.py']), @@ -58,15 +78,26 @@ def generate_launch_description(): 'town': 'Town02', 'register_all_sensors': 'False', 'ego_vehicle_role_name': 'hero', - 'timeout': '30' + 'timeout': '30', + 'fixed_delta_seconds': '0.1' }.items(), ) - state_estimation = Node( + gnss_processor = Node( package='state_estimation', executable='gnss_processing_node' ) + gnss_averager = Node( + package='state_estimation', + executable='gnss_averaging_node' + ) + + mcl = Node( + package='state_estimation', + executable='mcl_node' + ) + map_manager = Node( package='map_management', executable='map_management_node' @@ -74,9 +105,7 @@ def generate_launch_description(): rviz = Node( package='rviz2', - namespace='', executable='rviz2', - name='rviz2', arguments=['-d' + '/navigator/data/mcl.rviz'] ) @@ -90,30 +119,100 @@ def generate_launch_description(): executable='image_segmentation_node' ) + semantic_projection = Node( + package='segmentation', + executable='image_projection_node' + ) + + static_grid = Node( + package='occupancy_cpp', + executable='static_grid_exe' + ) + + grid_summation = Node( + package='costs', + executable='grid_summation_node' + ) + + junction_manager = Node( + package='costs', + executable='junction_manager' + ) + + rqt = Node( + package='rqt_gui', + executable='rqt_gui', + arguments=["--perspective-file=/navigator/data/rqt.perspective"] + ) + + route_reader = Node( + package='carla_interface', + executable='route_reader_node' + ) + + rtp = Node( + package='rtp', + executable='rtp_node' + ) + + prednet_inference = Node( + package='prednet_inference', + executable='prednet_inference_node' + ) + + web_bridge = Node( + package='rosbridge_server', + executable='rosbridge_websocket' + ) + + guardian = Node( + package='guardian', + executable='guardian_node' + ) + return LaunchDescription([ # CONTROL - carla_controller, + # carla_controller, # INTERFACE - # carla_bridge_official, - # carla_spawner, + carla_bridge_official, + carla_spawner, leaderboard_liaison, + web_bridge, + joy_linux, + joy_translation, # LOCALIZATION - # mcl + # gnss_averager, + # mcl, # MAPPING # MISC urdf_publisher, - rviz, + # rviz, + # rqt, + camera_streamer, # PERCEPTION - image_segmentation, + # image_segmentation, + # semantic_projection, lidar_processor, ground_seg, + static_grid, + # prednet_inference, + + # PLANNING + grid_summation, + route_reader, + junction_manager, + rtp, + + # SAFETY + airbags, + # guardian, # STATE ESTIMATION - # map_manager, - state_estimation, + map_manager, + # gnss_processor, ]) diff --git a/src/interface/carla_interface/launch/lite.launch.py b/src/interface/carla_interface/launch/lite.launch.py deleted file mode 100755 index 8122f87c3..000000000 --- a/src/interface/carla_interface/launch/lite.launch.py +++ /dev/null @@ -1,54 +0,0 @@ -''' -Spawn all nodes needed to connect to and drive in the CARLA -simulator WITHOUT Leaderboard evaluation. This speeds up load times -and therefore facilitates quick iteration. - -WSH. -''' - -from os import name, path, environ - -from launch.launch_description_sources import PythonLaunchDescriptionSource -from launch.actions import IncludeLaunchDescription -from launch import LaunchDescription -from launch.actions import DeclareLaunchArgument -from launch.actions import ExecuteProcess -from launch.conditions import IfCondition -from launch.substitutions import LaunchConfiguration -from launch_ros.actions import Node - -from ament_index_python import get_package_share_directory - - -def generate_launch_description(): - - carla_spawner = IncludeLaunchDescription( - PythonLaunchDescriptionSource([get_package_share_directory( - 'carla_spawn_objects'), '/carla_spawn_objects.launch.py']), - launch_arguments={ - 'objects_definition_file': '/navigator/data/carla_objects.json'}.items(), - ) - - carla_bridge_official = IncludeLaunchDescription( - PythonLaunchDescriptionSource([get_package_share_directory( - 'carla_ros_bridge'), '/carla_ros_bridge.launch.py']), - launch_arguments={ - 'host': 'localhost', - 'port': str(2000 + int(environ['ROS_DOMAIN_ID'])), - 'synchronous_mode': 'True', - 'town': 'Town01', - 'register_all_sensors': 'False', - 'ego_vehicle_role_name': 'hero' - }.items(), - ) - - main_launch = IncludeLaunchDescription( - PythonLaunchDescriptionSource( - [get_package_share_directory('carla_interface'), '/carla.launch.py']) - ) - - return LaunchDescription([ - carla_spawner, - carla_bridge_official, - main_launch - ]) diff --git a/src/interface/carla_interface/setup.py b/src/interface/carla_interface/setup.py index 86e3f88d3..4ba563d97 100755 --- a/src/interface/carla_interface/setup.py +++ b/src/interface/carla_interface/setup.py @@ -23,7 +23,8 @@ tests_require=['pytest'], entry_points={ 'console_scripts': [ - 'liaison_node = carla_interface.liaison_node:main' + 'liaison_node = carla_interface.liaison_node:main', + 'route_reader_node = carla_interface.route_reader:main' ], }, ) diff --git a/src/perception/ground_seg/ground_seg/__init__.py b/src/interface/epas/epas/__init__.py similarity index 100% rename from src/perception/ground_seg/ground_seg/__init__.py rename to src/interface/epas/epas/__init__.py diff --git a/src/interface/epas/epas/epas_node.py b/src/interface/epas/epas/epas_node.py new file mode 100644 index 000000000..7bafb85d0 --- /dev/null +++ b/src/interface/epas/epas/epas_node.py @@ -0,0 +1,142 @@ +import can +import math +from rosgraph_msgs.msg import Clock + + +from carla_msgs.msg import CarlaEgoVehicleControl +import rclpy +from rclpy.node import Node +from dataclasses import dataclass + + +@dataclass +class EpasState(): + duty: int + current: int + supply_voltage_mv: int + temperature: int + angle: int + errors: int + + +class EpasNode(Node): + + def __init__(self): + super().__init__('epas_node') + + self.limit_left:int = 19 + self.limit_right:int = 230 + + self.bus = can.interface.Bus(bustype='slcan', channel='/dev/serial/by-id/usb-Protofusion_Labs_CANable_1205aa6_https:__github.com_normaldotcom_cantact-fw_001500174E50430520303838-if00', bitrate=500000, receive_own_messages=True) + self.command_sub = self.create_subscription( + CarlaEgoVehicleControl, '/carla/hero/vehicle_control_cmd', self.first_sub, 1) + self.cmd_msg = None + self.cmd_timer = self.create_timer(.01,self.vehicleControlCb) + self.current_angle = 0.0 + self.target_angle = 0.0 + self.cached_msg1 = None + + def first_sub(self,msg: CarlaEgoVehicleControl): + self.cmd_msg = msg + + def parseIncomingMessages(self, msg1_data: bytearray, msg2_data: bytearray) -> EpasState: + torque = msg1_data[0] + duty = msg1_data[1] + current = msg1_data[2] + supply_voltage = msg1_data[3] + switch_pos = msg1_data[4] + temp = msg1_data[5] + torque_a = msg1_data[6] + torque_b = msg1_data[7] + + angle = msg2_data[0] + analog_c1 = msg2_data[1] + analog_c2 = msg2_data[2] + selected_map = msg2_data[3] + errors = msg2_data[4] + dio_bitfield = msg2_data[5] + status_bitfield = msg2_data[6] + limit_bitfield = msg2_data[7] + + current_state = EpasState( + duty, current, supply_voltage, temp, angle, errors) + + return current_state + + def sendCommand(self, target, bus): + current_angle_normalized = ((self.current_angle-self.limit_left)/(self.limit_right-self.limit_left)*2)-1 + #self.get_logger().info('current angle'+str(current_angle_normalized)) + e = target - current_angle_normalized # Error = target - current + self.get_logger().info('current_angle_normalized: '+str(current_angle_normalized)) + self.get_logger().info('target: '+str(target)) + + # We need to map [-1.0, 1.0] to [0, 255] + + Kp = 1 + + power = e * Kp # Power is an abstract value from [-1., 1.], where -1 is hard push left + + torqueA: int = min(255, max(0, math.ceil((power+1) * (255/2)))) + torqueB: int = 255-torqueA + + print (f"{torqueA}") + #self.get_logger().info(str(torqueA)) + + data = [0x03, torqueA, torqueB, 0x00, 0x00, 0x00, 0x00, 0x00] + message = can.Message(arbitration_id=0x296, data=data, check=True, is_extended_id=False) + bus.send(message, timeout=0.2) + + print (f"{torqueA}") + # print(e) + + def vehicleControlCb(self): + if self.cmd_msg!=None: + self.target_angle = self.cmd_msg.steer + #self.get_logger().info(str(msg.steer)) + + + response_msg = self.bus.recv(0.1) + if (response_msg is None): + print("No message received") + elif (response_msg.arbitration_id == 0x290): + self.cached_msg1 = response_msg.data + elif (response_msg.arbitration_id == 0x292): + if (self.cached_msg1 is None): + return + msg1 = self.cached_msg1 + msg2 = response_msg.data + current_state = self.parseIncomingMessages(msg1, msg2) + self.current_angle = current_state.angle + + #self.get_logger().info(str(self.current_angle)) + + # self.get_logger().info(f"Target: {self.target_angle}, current: {self.current_angle}") + + self.sendCommand(self.target_angle, self.bus) + + # current_angle_norm = ( + # (self.current_angle-self.limit_left)/(self.limit_right-self.limit_left)*2)-1 + # self.error = self.target_angle-current_angle_norm + # self.torque_a = int( + # min(255, max(0, math.ceil((self.error+1) * (255/2))))) + # self.torque_b = 255-self.torque_a + + # data = [0x03, self.torque_a, self.torque_b, + # 0x00, 0x00, 0x00, 0x00, 0x00] + # message = can.Message(arbitration_id=0x296, data=data, + # check=True, is_extended_id=False) + # self.bus.send(message, timeout=0.2) + + # The EPAS sends response info in two halves, each its own + # kind of CAN message. Combining the two gives us a complete state + # of the EPAS. Let's combine the two now. + + + + +def main(args=None): + rclpy.init(args=args) + epas_node = EpasNode() + rclpy.spin(epas_node) + epas_node.destroy_node() + rclpy.shutdown() diff --git a/src/interface/epas/package.xml b/src/interface/epas/package.xml new file mode 100755 index 000000000..c50150129 --- /dev/null +++ b/src/interface/epas/package.xml @@ -0,0 +1,16 @@ + + + + epas + 1.0.0 + Nodes for processing vehicle turn data and contacting CAN + Ashwin Somasundaram + MIT + + ament_lint_auto + ament_lint_common + + + ament_python + + diff --git a/src/mapping/map_management_old/COLCON_IGNORE b/src/interface/epas/resource/epas old mode 100644 new mode 100755 similarity index 100% rename from src/mapping/map_management_old/COLCON_IGNORE rename to src/interface/epas/resource/epas diff --git a/src/interface/epas/setup.cfg b/src/interface/epas/setup.cfg new file mode 100755 index 000000000..cece4d1d9 --- /dev/null +++ b/src/interface/epas/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/epas +[install] +install-scripts=$base/lib/epas diff --git a/src/tools/nova_viz/setup.py b/src/interface/epas/setup.py similarity index 89% rename from src/tools/nova_viz/setup.py rename to src/interface/epas/setup.py index 7aff2855b..6fc927b76 100755 --- a/src/tools/nova_viz/setup.py +++ b/src/interface/epas/setup.py @@ -2,7 +2,7 @@ from glob import glob import os -package_name = 'nova_viz' +package_name = 'epas' setup( name=package_name, @@ -23,7 +23,7 @@ tests_require=['pytest'], entry_points={ 'console_scripts': [ - 'nova_viz_exe = nova_viz.nova_viz_exe:main', + 'epas_node = epas.epas_node:main', ], }, ) diff --git a/src/tools/nova_viz/nova_viz/__init__.py b/src/interface/joy_translation/joy_translation/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from src/tools/nova_viz/nova_viz/__init__.py rename to src/interface/joy_translation/joy_translation/__init__.py diff --git a/src/interface/joy_translation/joy_translation/joy_translation_node.py b/src/interface/joy_translation/joy_translation/joy_translation_node.py new file mode 100644 index 000000000..42c9d2d68 --- /dev/null +++ b/src/interface/joy_translation/joy_translation/joy_translation_node.py @@ -0,0 +1,97 @@ +''' +Package: joy_translation +Filename: joy_translation_node.py +Author: Ashwin Somasundaram, Will Heitman (w at heit.mn) + +Converts Joy messages to vehicle control commands + +Xbox One controller axes: +[0]: LS, X +[1]: LS, Y +[2]: LT +[3]: LS, X +[4]: LS, Y +[5]: RT +[6]: Dpad X +[7]: Dpad Y + +Xbox One controller buttons: +[0]: A +[1]: B +[2]: X +[3]: Y +[4]: LB +[5]: RB +[6]: Select (left) +[7]: Start (right) +[8]: Xbox +[9]: LSB +[10]: RSB + +Controls: +A: Auto enable (hold) +X: Manual enable (hold, takes precedence over A) +LS: Steering position +LT: Brake +RT: Throttle + +Subscribes to: + /joy (sensor_msgs/Joy) + +Publishes to: +/carla/hero/vehicle_control_cmd (CarlaEgoVehicleControl) +''' + +import numpy as np +from rosgraph_msgs.msg import Clock +import time + +from carla_msgs.msg import CarlaEgoVehicleControl +from nova_msgs.msg import Mode +import rclpy +from rclpy.node import Node +from sensor_msgs.msg import Joy + + +class joy_translation_node(Node): + current_mode = Mode.DISABLED + + def __init__(self): + super().__init__('joy_translation_node') + self.joy_sub = self.create_subscription( + Joy, '/joy', self.joyCb, 10) + + def process_joy(self, joy_msg: Joy): + #self.get_logger().info('bruh') + msg = CarlaEgoVehicleControl() + msg.header.stamp = Clock().clock + msg.header.frame_id = 'base_link' + msg.throttle = ((joy_msg.axes[5]*-1)+1)/2 + + # TODO: Fix this jank. + if command_msg.throttle == 0.5: + command_msg.throttle = 0.0 + + msg.steer = joy_msg.axes[0]*-1 + + if abs(msg.steer)<0.2: + msg.steer = 0.0 + #self.get_logger().info(str(msg.steer)) + msg.brake = joy_msg.axes[2] + + #self.get_logger().info('this is the val of brake sent in') + #self.get_logger().info(str(msg.brake)) + msg.hand_brake = True if joy_msg.buttons[2]==1 else False + msg.reverse = True if joy_msg.buttons[0]==1 else False + msg.gear = True if joy_msg.buttons[3]==1 else False + msg.manual_gear_shift = True if joy_msg.buttons[1]==1 else False + self.output_msg.publish(msg) + + +def main(args=None): + rclpy.init(args=args) + joy_translator = joy_translation_node() + rclpy.spin(joy_translator) + + joy_translation_node.destroy_node() + rclpy.shutdown() diff --git a/src/interface/joy_translation/package.xml b/src/interface/joy_translation/package.xml new file mode 100755 index 000000000..a61f4acd7 --- /dev/null +++ b/src/interface/joy_translation/package.xml @@ -0,0 +1,16 @@ + + + + joy_translation + 1.0.0 + Nodes for processing vehicle turn data through the XBOX controller + Will Heitman + MIT + + ament_lint_auto + ament_lint_common + + + ament_python + + diff --git a/src/mapping/map_management_old/resource/map_management b/src/interface/joy_translation/resource/joy_translation similarity index 100% rename from src/mapping/map_management_old/resource/map_management rename to src/interface/joy_translation/resource/joy_translation diff --git a/src/interface/joy_translation/setup.cfg b/src/interface/joy_translation/setup.cfg new file mode 100755 index 000000000..8c869c236 --- /dev/null +++ b/src/interface/joy_translation/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/joy_translation +[install] +install-scripts=$base/lib/joy_translation diff --git a/src/mapping/map_management_old/setup.py b/src/interface/joy_translation/setup.py similarity index 78% rename from src/mapping/map_management_old/setup.py rename to src/interface/joy_translation/setup.py index 978550460..ef0a04710 100755 --- a/src/mapping/map_management_old/setup.py +++ b/src/interface/joy_translation/setup.py @@ -2,7 +2,7 @@ from glob import glob import os -package_name = 'map_management' +package_name = 'joy_translation' setup( name=package_name, @@ -23,7 +23,8 @@ tests_require=['pytest'], entry_points={ 'console_scripts': [ - 'map_management_node = map_management.map_management_node:main', + #'dynamic_grid_node = dynamic_grid.dynamic_grid_node:main', + 'joy_translation_node = joy_translation.joy_translation_node:main', ], - } + }, ) diff --git a/src/interface/linear_actuator/CMakeLists.txt b/src/interface/linear_actuator/CMakeLists.txt deleted file mode 100755 index 514f6d150..000000000 --- a/src/interface/linear_actuator/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Filename: CMakeLists.txt -# Author: Joshua Williams -# Email: joshmackwilliams@protonmail.com -# Copyright: 2021, Nova UTD -# License: MIT License - -# No package name is specified above since this is our standard -# CMakeLists.txt file and will be the same across multiple -# projects. To use it, just add nova_auto_package as a -# buildtool_depend in package.xml and copy this file into the root of -# your package. - -cmake_minimum_required(VERSION 3.5) -get_filename_component(directory_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) -project(${directory_name}) - -find_package(nova_auto_package REQUIRED) -nova_auto_package() diff --git a/src/interface/linear_actuator/exe/controller.cpp b/src/interface/linear_actuator/exe/controller.cpp deleted file mode 100755 index a5f330a70..000000000 --- a/src/interface/linear_actuator/exe/controller.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Package: linear_actuator - * Filename: controller.cpp - * Author: Joshua Williams - * Email: joshmackwilliams@protonmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -#include // std::make_shared -#include "rclcpp/rclcpp.hpp" -#include "linear_actuator/ControllerNode.hpp" - -int main(int argc, char ** argv) { - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} diff --git a/src/interface/linear_actuator/include/linear_actuator/ControllerNode.hpp b/src/interface/linear_actuator/include/linear_actuator/ControllerNode.hpp deleted file mode 100755 index d22f58fac..000000000 --- a/src/interface/linear_actuator/include/linear_actuator/ControllerNode.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Package: linear_actuator - * Filename: include/linear_actuator/ControllerNode.hpp - * Author: Joshua Williams - * Email: joshmackwilliams@protonmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -#pragma once - -#include // Time literals -#include - -#include "rclcpp/rclcpp.hpp" -#include "nova_msgs/msg/can_frame.hpp" -#include "std_msgs/msg/float32.hpp" - -#include "linear_actuator/controller_params.hpp" -#include "linear_actuator/types.hpp" - -using namespace std::chrono_literals; - -namespace navigator { -namespace linear_actuator { - -class ControllerNode : public rclcpp::Node { -public: - ControllerNode(); - ControllerNode(controller_params params); - virtual ~ControllerNode(); - -private: - void send_control_message(); - void update_target_position(const std_msgs::msg::Float32::SharedPtr position); - void init(); - - float target_position; - controller_params params; - - rclcpp::Publisher::SharedPtr can_publisher; - rclcpp::Subscription::SharedPtr position_subscription; - rclcpp::TimerBase::SharedPtr control_timer; -}; -} -} diff --git a/src/interface/linear_actuator/include/linear_actuator/controller_params.hpp b/src/interface/linear_actuator/include/linear_actuator/controller_params.hpp deleted file mode 100755 index f2f412b86..000000000 --- a/src/interface/linear_actuator/include/linear_actuator/controller_params.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Package: linear_actuator - * Filename: include/linear_actuator/controller_params.hpp - * Author: Joshua Williams - * Email: joshmackwilliams@protonmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -#pragma once - -#include "linear_actuator/types.hpp" - -namespace navigator { -namespace linear_actuator { - -struct controller_params { - int disengaged_position; - int engaged_position; - can_id_t command_id; -}; - -} -} diff --git a/src/interface/linear_actuator/include/linear_actuator/types.hpp b/src/interface/linear_actuator/include/linear_actuator/types.hpp deleted file mode 100755 index ee200079f..000000000 --- a/src/interface/linear_actuator/include/linear_actuator/types.hpp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Package: linear_actuator - * Filename: include/linear_actuator/types.hpp - * Author: Joshua Williams - * Email: joshmackwilliams@protonmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -#pragma once - -#include - -namespace navigator { -namespace linear_actuator { - -typedef uint32_t can_id_t; -typedef uint64_t can_data_t; - -} -} diff --git a/src/perception/ROSOccupancyGridPrediction/COLCON_IGNORE b/src/interface/linear_actuator/linear_actuator/__init__.py old mode 100644 new mode 100755 similarity index 100% rename from src/perception/ROSOccupancyGridPrediction/COLCON_IGNORE rename to src/interface/linear_actuator/linear_actuator/__init__.py diff --git a/src/interface/linear_actuator/linear_actuator/linear_actuator_node.py b/src/interface/linear_actuator/linear_actuator/linear_actuator_node.py new file mode 100755 index 000000000..547ef39a7 --- /dev/null +++ b/src/interface/linear_actuator/linear_actuator/linear_actuator_node.py @@ -0,0 +1,281 @@ +''' +Package: linear_actuator +Filename: linear_actuator_node.py +Author: Will Heitman (w at heit.mn) + +Subscribes to CarlaEgoVehicleControl messages (https://github.com/carla-simulator/ros-carla-msgs/blob/leaderboard-2.0/msg/CarlaEgoVehicleControl.msg) + +Sends the appropriate brake data to the LA +''' + +import os +import random +import time + +import can +import rclpy +from carla_msgs.msg import CarlaEgoVehicleControl +from rclpy.node import Node +from rclpy.qos import DurabilityPolicy, QoSProfile + +#bus = None +COMMAND_ID = 0xFF0000 +REPORT_ID = 0xFF0001 + + +class linear_actuator_node(Node): + vehicle_command_sub = None + brake = None + def __init__(self): + super().__init__('linear_actuator_node') + + self.vehicle_command_sub = self.create_subscription(CarlaEgoVehicleControl, '/carla/hero/vehicle_control_cmd', self.sendBrakeControl, 10) + #self.get_logger().info(str(vehicle_command_sub)) + #self.brake = 0.0 # 0.0 is released, 1.0 is fully pressed + self.get_logger().info("Bus now connected.") + + channel = '/dev/serial/by-id/usb-Protofusion_Labs_CANable_1205aa6_https:__github.com_normaldotcom_cantact-fw_001C000F4E50430120303838-if00' + bitrate = 250000 + self.bus = can.interface.Bus(bustype='slcan', channel=channel, bitrate=bitrate, receive_own_messages=True) + + while self.bus is None: + self.get_logger().warn("Bus not yet set. Waiting...") + time.sleep(1.0) + + self.get_logger().info("Bus now connected.") + response = self.enableClutch(self.bus) + self.get_logger().debug(f"Clutch enabled with response {response}") + + #self.brake_control_timer = self.create_timer( + #0.1, self.sendBrakeControl(self.bus)) + + def commandCb(self, msg: CarlaEgoVehicleControl): + self.brake = msg.brake + self.get_logger().info('this is the val of the brake currently') + self.get_logger().info(str(self.brake)) + + def sendBrakeControl(self, msg: CarlaEgoVehicleControl): + #self.get_logger().info('Printing self.brake in sendBrakeControl') + #self.get_logger().info(str(msg.brake)) + if self.bus is None: + self.get_logger().warn("Bus not yet set. Skipping command") + if msg.brake < 0.0: + msg.brake = 0.0 + elif msg.brake == 0.0: + msg.brake = 1.0 + response = self.sendToPosition(msg.brake, self.bus) + print(response) + + def enableClutch(self, bus: can.Bus): + clutch_enable = True + motor_enable = False + clutch_enable_byte = clutch_enable * 0x80 + motor_enable_byte = motor_enable * 0x40 + byte3 = clutch_enable_byte + motor_enable_byte + + data = [0x0F, 0x4A, 0, byte3, 0, 0, 0] + + message = can.Message( + arbitration_id=COMMAND_ID, data=data, is_extended_id=True) + + msg = bus.recv(0.1) + return msg + + def sendToPosition(self, pos: float, bus: can.Bus): + + #self.get_logger().info('hey im in the sendtoposition function') + """Given position, send appropriate CAN messages to LA + + Args: + pos (float): Position from 0.0 (fully extended) to 1.0 (fully retracted) + + Position command format: + [0x0F 0x4A DPOS_LOW Byte3 0 0 0 0] + + Byte 3: + [ClutchEnable MotorEnable POS7 POS6 POS5 POS4 POS3] + """ + + POSITION_MAX = 3.45 + POSITION_MIN = 0.80 + range = POSITION_MAX - POSITION_MIN + pos_inches = pos * range + POSITION_MIN + + # Account for 0.5 inch offset + pos_value = int(pos_inches * 1000) + 500 + + dpos_hi = int(pos_value / 0x100) + dpos_low = pos_value % 0x100 + + clutch_enable = True + motor_enable = True + clutch_enable_byte = clutch_enable * 0x80 + motor_enable_byte = motor_enable * 0x40 + byte3 = sum([dpos_hi, clutch_enable_byte, motor_enable_byte]) + + data = [0x0F, 0x4A, dpos_low, byte3, 0, 0, 0] + + message = can.Message( + arbitration_id=COMMAND_ID, data=data, is_extended_id=True) + + bus.send(message) + + msg = bus.recv(0.1) + + return msg + + +# class LAController: + +# def parseResponseMsg(self, msg: can.Message): +# if msg.data[0] == 0x98 and msg.data[1] == 0x00: +# self.parseEPR(msg) + +# else: +# print(msg) + +# def parseEPR(self, msg: can.Message): +# """Parse an Enhanced Position Report message + +# Args: +# msg (can.Message): EPR message + +# EPR message format: +# [0x98 0x00 ShaftA ShaftB Errors CurrentA CurrentB Status] +# """ + +# data = msg.data + +# # Parse int from shaftA, shaftB +# shaft_extension_inches = int.from_bytes( +# data[2:4], byteorder='little')*0.001 + +# # Parse errors +# fault_code = data[4] +# is_faulty = fault_code > 0 # True if one of the bit flags is set + +# # Parse current +# current_mA = int.from_bytes(data[5:7], byteorder='little') + +# print( +# f"Pos: {shaft_extension_inches} inches, status: {fault_code}, current: {current_mA} mA") + +# def enableClutch(self, bus: can.Bus): +# clutch_enable = True +# motor_enable = False +# clutch_enable_byte = clutch_enable * 0x80 +# motor_enable_byte = motor_enable * 0x40 +# byte3 = clutch_enable_byte + motor_enable_byte + +# data = [0x0F, 0x4A, 0, byte3, 0, 0, 0] + +# message = can.Message( +# arbitration_id=COMMAND_ID, data=data, is_extended_id=True) + +# msg = bus.recv(0.1) +# return msg + +# def disableClutch(self, bus: can.Bus): +# clutch_enable = False +# motor_enable = False +# clutch_enable_byte = clutch_enable * 0x80 +# motor_enable_byte = motor_enable * 0x40 +# byte3 = clutch_enable_byte + motor_enable_byte + +# data = [0x0F, 0x4A, 0, byte3, 0, 0, 0] + +# message = can.Message( +# arbitration_id=COMMAND_ID, data=data, is_extended_id=True) + +# msg = bus.recv(0.1) +# return msg + +# def sendToPosition(self, pos: float, bus: can.Bus): +# """Given position, send appropriate CAN messages to LA + +# Args: +# pos (float): Position from 0.0 (fully extended) to 1.0 (fully retracted) + +# Position command format: +# [0x0F 0x4A DPOS_LOW Byte3 0 0 0 0] + +# Byte 3: +# [ClutchEnable MotorEnable POS7 POS6 POS5 POS4 POS3] +# """ + +# POSITION_MAX = 3.45 +# POSITION_MIN = 0.80 +# range = POSITION_MAX - POSITION_MIN +# pos_inches = pos * range + POSITION_MIN + +# # Account for 0.5 inch offset +# pos_value = int(pos_inches * 1000) + 500 + +# dpos_hi = int(pos_value / 0x100) +# dpos_low = pos_value % 0x100 + +# clutch_enable = True +# motor_enable = True +# clutch_enable_byte = clutch_enable * 0x80 +# motor_enable_byte = motor_enable * 0x40 +# byte3 = sum([dpos_hi, clutch_enable_byte, motor_enable_byte]) + +# data = [0x0F, 0x4A, dpos_low, byte3, 0, 0, 0] +# # print(hex(clutch_enable_byte)) +# # print(hex(motor_enable_byte)) +# # print(hex(byte3)) + +# message = can.Message( +# arbitration_id=COMMAND_ID, data=data, is_extended_id=True) + +# bus.send(message) + +# msg = bus.recv(0.1) + +# return msg + +# def run(self, channel, bitrate): +# print("Opening bus... ", end="") +# bus = can.interface.Bus( +# bustype='slcan', channel=channel, bitrate=bitrate, receive_own_messages=True) +# print("Bus open.") + +# x = np.linspace(0.0, 4*np.pi, 201) +# positions = (np.sin(x) + 1.0) / 2 +# print(positions) + +# self.enableClutch(bus=bus) + +# for pos in tqdm(positions): +# response = self.sendToPosition(pos, bus=bus) +# time.sleep(0.05) +# # print(pos, end=" ") +# # self.parseResponseMsg(response) + +# self.disableClutch(bus=bus) + +# # self.sendToPosition(0.0, bus=bus) +# # time.sleep(0.4) +# # self.sendToPosition(0.5, bus=bus) +# # time.sleep(1.4) +# # self.sendToPosition(1.0, bus=bus) +# # time.sleep(2.4) + + +def main(args=None): + rclpy.init(args=args) + + LAN = linear_actuator_node() + + + rclpy.spin(LAN) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + linear_actuator_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/interface/linear_actuator/package.xml b/src/interface/linear_actuator/package.xml index c396c22b1..121289075 100755 --- a/src/interface/linear_actuator/package.xml +++ b/src/interface/linear_actuator/package.xml @@ -2,19 +2,12 @@ linear_actuator - 0.0.0 - ROS nodes to control linear actuators - Joshua Williams - MIT License - - nova_auto_package - - rclcpp - nova_msgs - - voltron_test_utils + 1.1.0 + Simple package to interface with a Kar-Tech CAN linear actuator + Will Heitman + MIT - ament_cmake + ament_python diff --git a/src/perception/dynamic_grid/resource/dynamic_grid b/src/interface/linear_actuator/resource/linear_actuator similarity index 100% rename from src/perception/dynamic_grid/resource/dynamic_grid rename to src/interface/linear_actuator/resource/linear_actuator diff --git a/src/interface/linear_actuator/setup.cfg b/src/interface/linear_actuator/setup.cfg new file mode 100755 index 000000000..0fb8a11df --- /dev/null +++ b/src/interface/linear_actuator/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/linear_actuator +[install] +install-scripts=$base/lib/linear_actuator diff --git a/src/interface/linear_actuator/setup.py b/src/interface/linear_actuator/setup.py new file mode 100755 index 000000000..b5cf907eb --- /dev/null +++ b/src/interface/linear_actuator/setup.py @@ -0,0 +1,29 @@ +from setuptools import setup +from glob import glob +import os + +package_name = 'linear_actuator' + +setup( + name=package_name, + version='1.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + (os.path.join('share', package_name), glob('launch/*.launch.py')) + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='Nova at UT Dallas', + maintainer_email='project.nova@utdallas.edu', + description='See package.xml', + license='MIT', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'linear_actuator_node = linear_actuator.linear_actuator_node:main' + ], + }, +) diff --git a/src/interface/linear_actuator/src/ControllerNode.cpp b/src/interface/linear_actuator/src/ControllerNode.cpp deleted file mode 100755 index 7c85136a1..000000000 --- a/src/interface/linear_actuator/src/ControllerNode.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Package: linear_actuator - * Filename: src/ControllerNode.cpp - * Author: Joshua Williams - * Email: joshmackwilliams@protonmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -#include -#include -#include -#include "rclcpp/rclcpp.hpp" -#include "nova_msgs/msg/can_frame.hpp" -#include "std_msgs/msg/float32.hpp" - -#include "linear_actuator/ControllerNode.hpp" - -using namespace navigator::linear_actuator; - -ControllerNode::ControllerNode() : Node("linear_actuator") { - this->declare_parameter("engaged_position"); - this->declare_parameter("disengaged_position"); - this->declare_parameter("command_id"); - this->get_parameter("engaged_position", this->params.engaged_position); - this->get_parameter("disengaged_position", this->params.disengaged_position); - this->get_parameter("command_id", this->params.command_id); - this->init(); -} - -ControllerNode::ControllerNode(controller_params params) : Node("linear_actuator") { - this->params = params; - this->init(); -} - -ControllerNode::~ControllerNode() {} - -void ControllerNode::init() { - this->can_publisher = this->create_publisher - ("outgoing_can_frames", 8); - this->position_subscription = this->create_subscription - ("target_position", 8, bind(& ControllerNode::update_target_position, this, std::placeholders::_1)); - this->control_timer = this->create_wall_timer(100ms, - bind(& ControllerNode::send_control_message, this)); -} - -void ControllerNode::send_control_message() { - can_data_t target_position = (can_data_t) std::lerp( - (float) this->params.disengaged_position, - (float) this->params.engaged_position, - this->target_position); - - auto message = nova_msgs::msg::CanFrame(); - message.identifier = this->params.command_id; - message.data = 0x00000000C0000A0F; - message.data = message.data | target_position << 16; - - this->can_publisher->publish(message); -} - -void ControllerNode::update_target_position(const std_msgs::msg::Float32::SharedPtr message) { - this->target_position = message->data; -} diff --git a/src/perception/ground_seg/resource/ground_seg b/src/interface/mcu_interface/mcu_interface/__init__.py old mode 100644 new mode 100755 similarity index 100% rename from src/perception/ground_seg/resource/ground_seg rename to src/interface/mcu_interface/mcu_interface/__init__.py diff --git a/src/interface/mcu_interface/mcu_interface/mcu_interface_node.py b/src/interface/mcu_interface/mcu_interface/mcu_interface_node.py new file mode 100755 index 000000000..59243b51f --- /dev/null +++ b/src/interface/mcu_interface/mcu_interface/mcu_interface_node.py @@ -0,0 +1,108 @@ +''' +Package: mcu_interface +Filename: mcu_interface_node.py +Author: Jai Peris + +Subscribes to CarlaEgoVehicleControl messages (https://github.com/carla-simulator/ros-carla-msgs/blob/leaderboard-2.0/msg/CarlaEgoVehicleControl.msg) + +Sends the appropriate brake data to the LA +''' + +import os +import random +import time +import io + +import serial +import rclpy +from carla_msgs.msg import CarlaEgoVehicleControl +from rclpy.node import Node +from rclpy.qos import DurabilityPolicy, QoSProfile + +bus = None +COMMAND_ID = 0xFF0000 +REPORT_ID = 0xFF0001 + + +class McuInterfaceNode(Node): + + def __init__(self, bus): + super().__init__('mcu_interface_node') + + self.last_command_rcv_time = None + + self.vehicle_command_sub = self.create_subscription( + CarlaEgoVehicleControl, '/carla/hero/vehicle_control_cmd', self.commandCb, 1) + + self.brake = 0.0 # 0.0 is released, 1.0 is fully pressed + self.bus: serial.Serial = bus + + while bus is None: + self.get_logger().warn("Bus not yet set. Waiting...") + time.sleep(1.0) + + self.sio = io.TextIOWrapper(io.BufferedRWPair(self.bus, self.bus)) + + self.get_logger().info("Bus now connected.") + + # what is create_timer? -Jai + self.vehicle_command_timer = self.create_timer(.5, self.publishCommand) + self.throttle = 0 + + def commandCb(self, msg: CarlaEgoVehicleControl): + self.throttle = msg.throttle + print(f"Joystick Throttle: {self.throttle}\n") + + # publishes the number (0-1) received from the subscription + def publishCommand(self): + throttle = self.throttle + if throttle < 0.1: + return + throttle = min(throttle, 0.3) + self.get_logger().info(f"Throttle = {throttle}") + + # command = str.encode(f"$throttle,{throttle};\n") + # s stands for start and e stands for end + command = f"s{throttle}e\r".encode() + self.get_logger().info(f"Command: s{throttle}e") + self.bus.write(command) + + # self.sio.write(f"$throttle,{throttle};\n") + + response = self.sio.readline() + # self.get_logger().info(response) + # self.sio.flush() + + +def main(args=None): + rclpy.init(args=args) + + # Try ls /dev/seria/by-id + channel = '/dev/serial/by-id/usb-Adafruit_Industries_LLC_Grand_Central_M4_Express_BA3E99D033533853202020350D3B12FF-if00' + bitrate = 115200 + + bus = None + + while bus is None: + try: + bus = serial.Serial(channel, bitrate, timeout=1) + except Exception as e: + print(f"An error occured opening the bus: {e} Retrying...") + time.sleep(1.0) + + mcu_interface_node = McuInterfaceNode(bus) + + rclpy.spin(mcu_interface_node) + + # Close the serial connection + bus.close() + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + mcu_interface_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/interface/mcu_interface/package.xml b/src/interface/mcu_interface/package.xml new file mode 100755 index 000000000..302207c58 --- /dev/null +++ b/src/interface/mcu_interface/package.xml @@ -0,0 +1,13 @@ + + + + mcu_interface + 1.1.0 + Simple package to interface with a Kar-Tech CAN linear actuator + Will Heitman + MIT + + + ament_python + + diff --git a/src/planning/cost_map_maker/COLCON_IGNORE b/src/interface/mcu_interface/resource/mcu_interface similarity index 100% rename from src/planning/cost_map_maker/COLCON_IGNORE rename to src/interface/mcu_interface/resource/mcu_interface diff --git a/src/interface/mcu_interface/setup.cfg b/src/interface/mcu_interface/setup.cfg new file mode 100755 index 000000000..abd54e355 --- /dev/null +++ b/src/interface/mcu_interface/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/mcu_interface +[install] +install-scripts=$base/lib/mcu_interface diff --git a/src/interface/mcu_interface/setup.py b/src/interface/mcu_interface/setup.py new file mode 100755 index 000000000..b663454ed --- /dev/null +++ b/src/interface/mcu_interface/setup.py @@ -0,0 +1,29 @@ +from setuptools import setup +from glob import glob +import os + +package_name = 'mcu_interface' + +setup( + name=package_name, + version='1.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + (os.path.join('share', package_name), glob('launch/*.launch.py')) + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='Nova at UT Dallas', + maintainer_email='project.nova@utdallas.edu', + description='See package.xml', + license='MIT', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'mcu_interface_node = mcu_interface.mcu_interface_node:main' + ], + }, +) diff --git a/src/interface/nmea_navsat_driver/CHANGELOG.rst b/src/interface/nmea_navsat_driver/CHANGELOG.rst new file mode 100644 index 000000000..132c4f894 --- /dev/null +++ b/src/interface/nmea_navsat_driver/CHANGELOG.rst @@ -0,0 +1,118 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package nmea_navsat_driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +2.0.0 (2022-06-25) +------------------ + +* Replace dependency on transforms3d pip package to tf_transformations. (`#147 `_) +* Added log for successful connection. (`#149 `_) +* Removed printing every time the checksum is checked. (`#148 `_) +* nmea_socket_driver fixes for ROS2 (`#127 `_) + * Fix white space for PEP8 compliance + * Fix socket driver for ROS2 Foxy + * Add config file for socket driver + * Decode bytes as ASCII +* Fix bug where ROS node is not assigned correctly (`#114 `_) + Fixes `#71 `_ +* Update launch file for ROS2 Foxy (`#110 `_) + * Remove get_default_launch_description, which no longer exists. + * Update the parameters of the Node initializer to the Foxy API. +* Update pyserial dependency to make it findable with rosdep (`#109 `_) + This allows rosdep to find the correct serial package and install it. +* ROS2: Eloquent changes for python packages (`#101 `_) + Fix some warnings when installing packages that first appear in ROS2 Eloquent: + - A missing the resource folder + - Not explicitly installing package.xml in the share folder. +* ROS2 updates for Dashing (`#80 `_) + Change subscriptions and parameters to conform to API changes in ROS 2 Dashing. +* Remove scripts directory in favor of nodes subpackage (`#77 `_) + Since these modules will no longer be called as scripts in ROS 2, + move them to a nodes subpackage, and remove the option to call them + as executables. + Addresses `#75 `_ for ROS 2. +* Fix nmea_topic_serial_reader name (`#74 `_) + - Fix `#72 `_ (no module name scripts.nmea_topic_serial_driver) + - Fix exception handling in nmea_topic_serial_reader ('rclpy' has no attribute 'ROSInterruptException') +* Clean up launch file and make it runnable with ROS2 launch (`#73 `_) + Fixes `#70 `_ + - Rename config file and put it into a config directory. + - Make setup.py install the launch and config files. + - Rename the launch file with the .launch.py suffix used by OSRF + packages. + - Refactor the launch file so that it works with `ros2 launch`. +* Fix PEP8 Violations and update setup.cfg file for pycodestyle. (`#69 `_) +* Port to ROS 2 (`#64 `_) + Initial work to port nmea_navsat_driver to ROS2 by @klintan. +* Add nmea_serial_driver launch file (`#60 `_) + Add example nmea_serial_driver launch file. +* Remove automatic prefixing of forward slash to frame_id. (`#33 `_/`#57 `_) + To be consistent with the current default behavior, the default frame_id has been set to /gps with the prepended forward slash. +* Add support for IMU aided GPS systems (`#30 `_/`#58 `_) + * Add support for IMU aided GPS systems like the Applanix POS/MV, whose NMEA strings typically begin '$IN'. (e.g. $INGGA). + * Add support for VTG messages, which contain Course Over Ground and Speed Made Good. These are useful when not using RMC messages and you don't have a heading sensor. +* Add support for publishing heading from GPHDT as a QuaternionStamped message on the topic /heading (`#25 `_) +* Improve Covariance Estimation (`#46 `_) + Use GST covariance where available, otherwise uses default covariances estimated from fix type. + The previous implementation set covariance to HDOP^2. Instead, it should multiply that by the measurement variance. HDOP should be greater than 1.0. +* Add Socket Driver (`#32 `_) + Add a NMEA socket driver node, which is like the existing serial driver node, but instead of attaching to a TTY handle from a serial port, it listens to a UDP port for NMEA sentences. +* Add code to handle serial exception to allow node to exit cleanly (`#52 `_) + - Catch Serial exceptions and exit cleanly, instead of printing Python stack trace. + - Catch Serial exception when opening the serial port, log a FATAL message, and exit instead of printing Python stack trace. +* Remove MSL compensation (`#36 `_) + Fix for `#29 `_ Altitude vs Elipsoid Height. +* Add GLONASS support + GLONASS capable devices send different NMEA sentences, which are + basically identical to the GPS sentences, but with other prefixes. +* Updated driver to accept status of 9 which some novatel receivers report for a WAAS (SBAS) fix. + See http://www.novatel.com/support/known-solutions/which-novatel-position-types-correspond-to-the-gga-quality-indicator/ + +0.5.0 (2015-04-23) +------------------ +* Release to Jade. + +0.4.2 (2015-04-23) +------------------ +* Fix remaining parse problem with NovAtel receivers (empty field specified for num_satellite). + +0.4.1 (2014-08-03) +------------------ +* Add debug logging output to the parser (PR #8, Mike Purvis) +* Add queue size argument to publishers to fix warning on Indigo (PR #9, Mike Purvis) +* Add support for roslint and some related cleanup (PR #10, Mike Purvis) + +0.4.0 (2014-05-04) +------------------- +* Initial release for Indigo +* Fix #5: Empty fields spam rosout with warnings. Driver now outputs sensor_msgs/NavSatFix messages that may contain NaNs in position and covariance when receiving invalid fixes from the device. + +0.3.3 (2013-10-08) +------------------- +* Allow the driver to output velocity information anytime an RMC message is received + +0.3.2 (2013-07-21) +------------------- +* Moved to nmea_navsat_driver package +* Removed .py extensions from new-in-Hydro scripts +* Now uses nmea_msgs/Sentence instead of custom sentence type +* nmea_topic_driver reads the `frame_id` parameter from the sentence, not from the parameter server + +0.3.1 (2013-05-07) +------------------- +* Removed incorrect find_package dependencies + +0.3.0 (2013-05-05) +------------------- +* Initial release for Hydro +* Converted to Catkin +* nmea_gps_driver.py is now deprecated and will be removed in I-Turtle. Replacement node is nmea_serial_driver.py . +* Refactored code into NMEA parser, common ROS driver and separate nodes for reading directly from serial or from topic. +* Bugs fixed: + - nmea_gps_driver crashes when a sentence doesn't have a checksum * character ( http://kforge.ros.org/gpsdrivers/trac/ticket/4 ) + - Add ability for nmea_gps_driver to support reading from string topic ( https://github.com/ros-drivers/nmea_gps_driver/issues/1 ). Use the nmea_topic_driver.py node to get this support. + +0.2.0 (2012-03-15) +------------------ +* Initial version (released into Fuerte) +* Supports GGA or RMC+GSA sentences to generate sensor_msgs/NavSatFix messages diff --git a/src/interface/nmea_navsat_driver/README.rst b/src/interface/nmea_navsat_driver/README.rst new file mode 100644 index 000000000..398155693 --- /dev/null +++ b/src/interface/nmea_navsat_driver/README.rst @@ -0,0 +1,11 @@ +nmea_navsat_driver +=============== + +ROS driver to parse NMEA strings and publish standard ROS NavSat message types. Does not require the GPSD daemon to be running. + +API +--- + +This package has no released Code API. + +The ROS API documentation and other information can be found at http://ros.org/wiki/nmea_navsat_driver diff --git a/src/interface/nmea_navsat_driver/config/nmea_serial_driver.yaml b/src/interface/nmea_navsat_driver/config/nmea_serial_driver.yaml new file mode 100644 index 000000000..1e3b55d5f --- /dev/null +++ b/src/interface/nmea_navsat_driver/config/nmea_serial_driver.yaml @@ -0,0 +1,7 @@ +nmea_navsat_driver: + ros__parameters: + port: "/dev/tty.usbserial" + baud: 4800 + frame_id: "gps" + time_ref_source: "gps" + useRMC: False \ No newline at end of file diff --git a/src/interface/nmea_navsat_driver/config/nmea_socket_driver.yaml b/src/interface/nmea_navsat_driver/config/nmea_socket_driver.yaml new file mode 100644 index 000000000..8ca2f307a --- /dev/null +++ b/src/interface/nmea_navsat_driver/config/nmea_socket_driver.yaml @@ -0,0 +1,6 @@ +nmea_navsat_driver: + ros__parameters: + ip: "0.0.0.0" + port: 10110 + buffer_size: 4096 + timeout_sec: 2 diff --git a/src/interface/nmea_navsat_driver/config/nmea_tcpclient_driver.yaml b/src/interface/nmea_navsat_driver/config/nmea_tcpclient_driver.yaml new file mode 100644 index 000000000..c7a314199 --- /dev/null +++ b/src/interface/nmea_navsat_driver/config/nmea_tcpclient_driver.yaml @@ -0,0 +1,5 @@ +nmea_navsat_driver: + ros__parameters: + ip: "192.168.131.22" + port: 9001 + buffer_size: 4096 \ No newline at end of file diff --git a/src/interface/nmea_navsat_driver/launch/nmea_serial_driver.launch.py b/src/interface/nmea_navsat_driver/launch/nmea_serial_driver.launch.py new file mode 100644 index 000000000..77a4e5774 --- /dev/null +++ b/src/interface/nmea_navsat_driver/launch/nmea_serial_driver.launch.py @@ -0,0 +1,55 @@ +# Copyright 2018 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" A simple launch file for the nmea_serial_driver node. """ + +import os +import sys + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription, LaunchIntrospector, LaunchService +from launch_ros import actions + + +def generate_launch_description(): + """Generate a launch description for a single serial driver.""" + config_file = os.path.join(get_package_share_directory("nmea_navsat_driver"), "config", "nmea_serial_driver.yaml") + driver_node = actions.Node( + package='nmea_navsat_driver', + executable='nmea_serial_driver', + output='screen', + parameters=[config_file]) + + return LaunchDescription([driver_node]) + + +def main(argv): + ld = generate_launch_description() + + print('Starting introspection of launch description...') + print('') + + print(LaunchIntrospector().format_launch_description(ld)) + + print('') + print('Starting launch of launch description...') + print('') + + ls = LaunchService() + ls.include_launch_description(ld) + return ls.run() + + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/interface/nmea_navsat_driver/launch/nmea_socket_driver.launch.py b/src/interface/nmea_navsat_driver/launch/nmea_socket_driver.launch.py new file mode 100644 index 000000000..59ef40bad --- /dev/null +++ b/src/interface/nmea_navsat_driver/launch/nmea_socket_driver.launch.py @@ -0,0 +1,55 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" A simple launch file for the nmea_socket_driver node. """ + +import os +import sys + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription, LaunchIntrospector, LaunchService +from launch_ros import actions + + +def generate_launch_description(): + """Generate a launch description for a single socket driver.""" + config_file = os.path.join(get_package_share_directory("nmea_navsat_driver"), "config", "nmea_socket_driver.yaml") + driver_node = actions.Node( + package='nmea_navsat_driver', + executable='nmea_socket_driver', + output='screen', + parameters=[config_file]) + + return LaunchDescription([driver_node]) + + +def main(argv): + ld = generate_launch_description() + + print('Starting introspection of launch description...') + print('') + + print(LaunchIntrospector().format_launch_description(ld)) + + print('') + print('Starting launch of launch description...') + print('') + + ls = LaunchService() + ls.include_launch_description(ld) + return ls.run() + + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/interface/nmea_navsat_driver/launch/nmea_tcpclient_driver.launch.py b/src/interface/nmea_navsat_driver/launch/nmea_tcpclient_driver.launch.py new file mode 100644 index 000000000..7d31361e9 --- /dev/null +++ b/src/interface/nmea_navsat_driver/launch/nmea_tcpclient_driver.launch.py @@ -0,0 +1,55 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" A simple launch file for the nmea_tcpclient_driver node. """ + +import os +import sys + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription, LaunchIntrospector, LaunchService +from launch_ros import actions + + +def generate_launch_description(): + """Generate a launch description for a single tcpclient driver.""" + config_file = os.path.join(get_package_share_directory("nmea_navsat_driver"), "config", "nmea_tcpclient_driver.yaml") + driver_node = actions.Node( + package='nmea_navsat_driver', + executable='nmea_tcpclient_driver', + output='screen', + parameters=[config_file]) + + return LaunchDescription([driver_node]) + + +def main(argv): + ld = generate_launch_description() + + print('Starting introspection of launch description...') + print('') + + print(LaunchIntrospector().format_launch_description(ld)) + + print('') + print('Starting launch of launch description...') + print('') + + ls = LaunchService() + ls.include_launch_description(ld) + return ls.run() + + +if __name__ == '__main__': + main(sys.argv) diff --git a/src/interface/nmea_navsat_driver/package.xml b/src/interface/nmea_navsat_driver/package.xml new file mode 100644 index 000000000..612ee9bde --- /dev/null +++ b/src/interface/nmea_navsat_driver/package.xml @@ -0,0 +1,33 @@ + + + + nmea_navsat_driver + 2.0.0 + + Package to parse NMEA strings and publish a very simple GPS message. Does not + require or use the GPSD deamon. + + + Ed Venator + + BSD + + http://ros.org/wiki/nmea_navsat_driver + + Eric Perko + Steven Martin + + geometry_msgs + nmea_msgs + rclpy + sensor_msgs + python3-numpy + python3-serial + tf_transformations + + python3-pytest + + + ament_python + + diff --git a/src/planning/path_publisher/COLCON_IGNORE b/src/interface/nmea_navsat_driver/resource/nmea_navsat_driver similarity index 100% rename from src/planning/path_publisher/COLCON_IGNORE rename to src/interface/nmea_navsat_driver/resource/nmea_navsat_driver diff --git a/src/interface/nmea_navsat_driver/setup.cfg b/src/interface/nmea_navsat_driver/setup.cfg new file mode 100644 index 000000000..2d1bda2c1 --- /dev/null +++ b/src/interface/nmea_navsat_driver/setup.cfg @@ -0,0 +1,10 @@ +[develop] +script_dir=$base/lib/nmea_navsat_driver + +[install] +install_scripts=$base/lib/nmea_navsat_driver + +[pycodestyle] +max-line-length = 120 +statistics = True +show-pep8 = True diff --git a/src/interface/nmea_navsat_driver/setup.py b/src/interface/nmea_navsat_driver/setup.py new file mode 100644 index 000000000..88df5a20c --- /dev/null +++ b/src/interface/nmea_navsat_driver/setup.py @@ -0,0 +1,37 @@ +from glob import glob +import os +from setuptools import setup + +PACKAGE_NAME = "nmea_navsat_driver" +SHARE_DIR = os.path.join("share", PACKAGE_NAME) + +setup( + name=PACKAGE_NAME, + version='2.0.0', + packages=["libnmea_navsat_driver", "libnmea_navsat_driver.nodes"], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + PACKAGE_NAME]), + ('share/' + PACKAGE_NAME, ['package.xml']), + (os.path.join(SHARE_DIR, "launch"), glob(os.path.join("launch", "*.launch.py"))), + (os.path.join(SHARE_DIR, "config"), glob(os.path.join("config", "*.yaml")))], + package_dir={'': 'src', }, + py_modules=[], + zip_safe=True, + install_requires=['setuptools', + 'pyserial', + 'numpy', + 'pyyaml'], + author='Eric Perko', + maintainer='Ed Venator', + keywords=['ROS2'], + description='Package to parse NMEA strings and publish a very simple GPS message.', + license='BSD', + entry_points={ + 'console_scripts': ['nmea_serial_driver = libnmea_navsat_driver.nodes.nmea_serial_driver:main', + 'nmea_socket_driver = libnmea_navsat_driver.nodes.nmea_socket_driver:main', + 'nmea_tcpclient_driver = libnmea_navsat_driver.nodes.nmea_tcpclient_driver:main', + 'nmea_topic_driver = libnmea_navsat_driver.nodes.nmea_topic_driver:main', + 'nmea_topic_serial_reader = libnmea_navsat_driver.nodes.nmea_topic_serial_reader:main'], + } +) diff --git a/src/planning/zone_lib/COLCON_IGNORE b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/__init__.py similarity index 100% rename from src/planning/zone_lib/COLCON_IGNORE rename to src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/__init__.py diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/checksum_utils.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/checksum_utils.py new file mode 100644 index 000000000..822da92b1 --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/checksum_utils.py @@ -0,0 +1,48 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2013, Eric Perko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the names of the authors nor the names of their +# affiliated organizations may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +# Check the NMEA sentence checksum. Return True if passes and False if failed +def check_nmea_checksum(nmea_sentence): + split_sentence = nmea_sentence.split('*') + if len(split_sentence) != 2: + # No checksum bytes were found... improperly formatted/incomplete NMEA data? + return False + transmitted_checksum = split_sentence[1].strip() + + # Remove the $ at the front + data_to_checksum = split_sentence[0][1:] + checksum = 0 + for c in data_to_checksum: + checksum ^= ord(c) + + return ("%02X" % checksum) == transmitted_checksum.upper() diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/driver.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/driver.py new file mode 100644 index 000000000..82110b7a0 --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/driver.py @@ -0,0 +1,281 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2013, Eric Perko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the names of the authors nor the names of their +# affiliated organizations may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import math + +import rclpy + +from rclpy.node import Node +from sensor_msgs.msg import NavSatFix, NavSatStatus, TimeReference +from geometry_msgs.msg import TwistStamped, QuaternionStamped +from tf_transformations import quaternion_from_euler +from libnmea_navsat_driver.checksum_utils import check_nmea_checksum +from libnmea_navsat_driver import parser + + +class Ros2NMEADriver(Node): + def __init__(self): + super().__init__('nmea_navsat_driver') + + self.fix_pub = self.create_publisher(NavSatFix, 'fix', 10) + self.vel_pub = self.create_publisher(TwistStamped, 'vel', 10) + self.heading_pub = self.create_publisher(QuaternionStamped, 'heading', 10) + self.time_ref_pub = self.create_publisher(TimeReference, 'time_reference', 10) + + self.time_ref_source = self.declare_parameter('time_ref_source', 'gps').value + self.use_RMC = self.declare_parameter('useRMC', False).value + self.valid_fix = False + + # epe = estimated position error + self.default_epe_quality0 = self.declare_parameter('epe_quality0', 1000000).value + self.default_epe_quality1 = self.declare_parameter('epe_quality1', 4.0).value + self.default_epe_quality2 = self.declare_parameter('epe_quality2', 0.1).value + self.default_epe_quality4 = self.declare_parameter('epe_quality4', 0.02).value + self.default_epe_quality5 = self.declare_parameter('epe_quality5', 4.0).value + self.default_epe_quality9 = self.declare_parameter('epe_quality9', 3.0).value + + self.using_receiver_epe = False + + self.lon_std_dev = float("nan") + self.lat_std_dev = float("nan") + self.alt_std_dev = float("nan") + + """Format for this dictionary is the fix type from a GGA message as the key, with + each entry containing a tuple consisting of a default estimated + position error, a NavSatStatus value, and a NavSatFix covariance value.""" + self.gps_qualities = { + # Unknown + -1: [ + self.default_epe_quality0, + NavSatStatus.STATUS_NO_FIX, + NavSatFix.COVARIANCE_TYPE_UNKNOWN + ], + # Invalid + 0: [ + self.default_epe_quality0, + NavSatStatus.STATUS_NO_FIX, + NavSatFix.COVARIANCE_TYPE_UNKNOWN + ], + # SPS + 1: [ + self.default_epe_quality1, + NavSatStatus.STATUS_FIX, + NavSatFix.COVARIANCE_TYPE_APPROXIMATED + ], + # DGPS + 2: [ + self.default_epe_quality2, + NavSatStatus.STATUS_SBAS_FIX, + NavSatFix.COVARIANCE_TYPE_APPROXIMATED + ], + # RTK Fix + 4: [ + self.default_epe_quality4, + NavSatStatus.STATUS_GBAS_FIX, + NavSatFix.COVARIANCE_TYPE_APPROXIMATED + ], + # RTK Float + 5: [ + self.default_epe_quality5, + NavSatStatus.STATUS_GBAS_FIX, + NavSatFix.COVARIANCE_TYPE_APPROXIMATED + ], + # WAAS + 9: [ + self.default_epe_quality9, + NavSatStatus.STATUS_GBAS_FIX, + NavSatFix.COVARIANCE_TYPE_APPROXIMATED + ] + } + + # Returns True if we successfully did something with the passed in + # nmea_string + def add_sentence(self, nmea_string, frame_id, timestamp=None): + if not check_nmea_checksum(nmea_string): + self.get_logger().warn("Received a sentence with an invalid checksum. " + + "Sentence was: %s" % nmea_string) + return False + + parsed_sentence = parser.parse_nmea_sentence(nmea_string) + if not parsed_sentence: + self.get_logger().debug("Failed to parse NMEA sentence. Sentence was: %s" % nmea_string) + return False + + if timestamp: + current_time = timestamp + else: + current_time = self.get_clock().now().to_msg() + + current_fix = NavSatFix() + current_fix.header.stamp = current_time + current_fix.header.frame_id = frame_id + current_time_ref = TimeReference() + current_time_ref.header.stamp = current_time + current_time_ref.header.frame_id = frame_id + if self.time_ref_source: + current_time_ref.source = self.time_ref_source + else: + current_time_ref.source = frame_id + + if not self.use_RMC and 'GGA' in parsed_sentence: + current_fix.position_covariance_type = NavSatFix.COVARIANCE_TYPE_APPROXIMATED + + data = parsed_sentence['GGA'] + fix_type = data['fix_type'] + if not (fix_type in self.gps_qualities): + fix_type = -1 + gps_qual = self.gps_qualities[fix_type] + default_epe = gps_qual[0] + current_fix.status.status = gps_qual[1] + current_fix.position_covariance_type = gps_qual[2] + if current_fix.status.status > 0: + self.valid_fix = True + else: + self.valid_fix = False + + current_fix.status.service = NavSatStatus.SERVICE_GPS + latitude = data['latitude'] + if data['latitude_direction'] == 'S': + latitude = -latitude + current_fix.latitude = latitude + + longitude = data['longitude'] + if data['longitude_direction'] == 'W': + longitude = -longitude + current_fix.longitude = longitude + + # Altitude is above ellipsoid, so adjust for mean-sea-level + altitude = data['altitude'] + data['mean_sea_level'] + current_fix.altitude = altitude + + # use default epe std_dev unless we've received a GST sentence with epes + if not self.using_receiver_epe or math.isnan(self.lon_std_dev): + self.lon_std_dev = default_epe + if not self.using_receiver_epe or math.isnan(self.lat_std_dev): + self.lat_std_dev = default_epe + if not self.using_receiver_epe or math.isnan(self.alt_std_dev): + self.alt_std_dev = default_epe * 2 + + hdop = data['hdop'] + current_fix.position_covariance[0] = (hdop * self.lon_std_dev) ** 2 + current_fix.position_covariance[4] = (hdop * self.lat_std_dev) ** 2 + current_fix.position_covariance[8] = (2 * hdop * self.alt_std_dev) ** 2 # FIXME + + self.fix_pub.publish(current_fix) + + if not math.isnan(data['utc_time']): + current_time_ref.time_ref = rclpy.time.Time(seconds=data['utc_time']).to_msg() + self.last_valid_fix_time = current_time_ref + self.time_ref_pub.publish(current_time_ref) + + elif not self.use_RMC and 'VTG' in parsed_sentence: + data = parsed_sentence['VTG'] + + # Only report VTG data when you've received a valid GGA fix as well. + if self.valid_fix: + current_vel = TwistStamped() + current_vel.header.stamp = current_time + current_vel.header.frame_id = frame_id + current_vel.twist.linear.x = data['speed'] * math.sin(data['true_course']) + current_vel.twist.linear.y = data['speed'] * math.cos(data['true_course']) + self.vel_pub.publish(current_vel) + + elif 'RMC' in parsed_sentence: + data = parsed_sentence['RMC'] + + # Only publish a fix from RMC if the use_RMC flag is set. + if self.use_RMC: + if data['fix_valid']: + current_fix.status.status = NavSatStatus.STATUS_FIX + else: + current_fix.status.status = NavSatStatus.STATUS_NO_FIX + + current_fix.status.service = NavSatStatus.SERVICE_GPS + + latitude = data['latitude'] + if data['latitude_direction'] == 'S': + latitude = -latitude + current_fix.latitude = latitude + + longitude = data['longitude'] + if data['longitude_direction'] == 'W': + longitude = -longitude + current_fix.longitude = longitude + + current_fix.altitude = float('NaN') + current_fix.position_covariance_type = \ + NavSatFix.COVARIANCE_TYPE_UNKNOWN + + self.fix_pub.publish(current_fix) + + if not math.isnan(data['utc_time']): + current_time_ref.time_ref = rclpy.time.Time(seconds=data['utc_time']).to_msg() + self.time_ref_pub.publish(current_time_ref) + + # Publish velocity from RMC regardless, since GGA doesn't provide it. + if data['fix_valid']: + current_vel = TwistStamped() + current_vel.header.stamp = current_time + current_vel.header.frame_id = frame_id + current_vel.twist.linear.x = data['speed'] * math.sin(data['true_course']) + current_vel.twist.linear.y = data['speed'] * math.cos(data['true_course']) + self.vel_pub.publish(current_vel) + elif 'GST' in parsed_sentence: + data = parsed_sentence['GST'] + + # Use receiver-provided error estimate if available + self.using_receiver_epe = True + self.lon_std_dev = data['lon_std_dev'] + self.lat_std_dev = data['lat_std_dev'] + self.alt_std_dev = data['alt_std_dev'] + elif 'HDT' in parsed_sentence: + data = parsed_sentence['HDT'] + if data['heading']: + current_heading = QuaternionStamped() + current_heading.header.stamp = current_time + current_heading.header.frame_id = frame_id + q = quaternion_from_euler(0, 0, math.radians(data['heading'])) + current_heading.quaternion.x = q[0] + current_heading.quaternion.y = q[1] + current_heading.quaternion.z = q[2] + current_heading.quaternion.w = q[3] + self.heading_pub.publish(current_heading) + else: + return False + + """Helper method for getting the frame_id with the correct TF prefix""" + def get_frame_id(self): + frame_id = self.declare_parameter('frame_id', 'gps').value + prefix = self.declare_parameter('tf_prefix', '').value + if len(prefix): + return '%s/%s' % (prefix, frame_id) + return frame_id diff --git a/src/tools/nova_viz/resource/nova_viz b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/__init__.py old mode 100755 new mode 100644 similarity index 100% rename from src/tools/nova_viz/resource/nova_viz rename to src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/__init__.py diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_serial_driver.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_serial_driver.py new file mode 100755 index 000000000..ce6083858 --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_serial_driver.py @@ -0,0 +1,69 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2013, Eric Perko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the names of the authors nor the names of their +# affiliated organizations may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import serial + +import rclpy + +from libnmea_navsat_driver.driver import Ros2NMEADriver + + +def main(args=None): + rclpy.init(args=args) + + driver = Ros2NMEADriver() + frame_id = driver.get_frame_id() + + serial_port = driver.declare_parameter('port', '/dev/ttyUSB0').value + serial_baud = driver.declare_parameter('baud', 4800).value + + try: + GPS = serial.Serial(port=serial_port, baudrate=serial_baud, timeout=2) + driver.get_logger().info("Successfully connected to {0} at {1}.".format(serial_port, serial_baud)) + try: + while rclpy.ok(): + data = GPS.readline().strip() + try: + if isinstance(data, bytes): + data = data.decode("utf-8") + driver.add_sentence(data, frame_id) + except ValueError as e: + driver.get_logger().warn( + "Value error, likely due to missing fields in the NMEA message. Error was: %s. " + "Please report this issue at github.com/ros-drivers/nmea_navsat_driver, including a bag file " + "with the NMEA sentences that caused it." % e) + + except Exception as e: + driver.get_logger().error("Ros error: {0}".format(e)) + GPS.close() # Close GPS serial port + except serial.SerialException as ex: + driver.get_logger().fatal("Could not open serial port: I/O error({0}): {1}".format(ex.errno, ex.strerror)) diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_socket_driver.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_socket_driver.py new file mode 100755 index 000000000..da5dcadf9 --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_socket_driver.py @@ -0,0 +1,99 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2016, Rein Appeldoorn +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the names of the authors nor the names of their +# affiliated organizations may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import socket +import sys + +import rclpy + +from libnmea_navsat_driver.driver import Ros2NMEADriver + + +def main(args=None): + rclpy.init(args=args) + driver = Ros2NMEADriver() + + try: + local_ip = driver.declare_parameter('ip', '0.0.0.0').value + local_port = driver.declare_parameter('port', 10110).value + buffer_size = driver.declare_parameter('buffer_size', 4096).value + timeout = driver.declare_parameter('timeout_sec', 2).value + except KeyError as e: + driver.get_logger().err("Parameter %s not found" % e) + sys.exit(1) + + frame_id = driver.get_frame_id() + + driver.get_logger().info( + " Using parameters ip {} port {} buffer_size {} timeout_sec {}" + .format(local_ip, local_port, buffer_size, timeout)) + + # Connection-loop: connect and keep receiving. If receiving fails, reconnect + while rclpy.ok(): + try: + # Create a socket + socket_ = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + # Bind the socket to the port + socket_.bind((local_ip, local_port)) + + # Set timeout + socket_.settimeout(timeout) + except socket.error as exc: + driver.get_logger().error("Caught exception socket.error when setting up socket: %s" % exc) + sys.exit(1) + + # recv-loop: When we're connected, keep receiving stuff until that fails + while rclpy.ok(): + try: + data, remote_address = socket_.recvfrom(buffer_size) + + # strip the data + data_list = data.decode("ascii").strip().split("\n") + + for data in data_list: + + try: + driver.add_sentence(data, frame_id) + except ValueError as e: + driver.get_logger().warn( + "Value error, likely due to missing fields in the NMEA message. " + "Error was: %s. Please report this issue at github.com/ros-drivers/nmea_navsat_driver, " + "including a bag file with the NMEA sentences that caused it." % e) + + except socket.error as exc: + driver.get_logger().error("Caught exception socket.error during recvfrom: %s" % exc) + socket_.close() + # This will break out of the recv-loop so we start another iteration of the connection-loop + break + + socket_.close() # Close socket diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_tcpclient_driver.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_tcpclient_driver.py new file mode 100644 index 000000000..d06a1ff07 --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_tcpclient_driver.py @@ -0,0 +1,83 @@ +# Copyright 2022 Open Source Robotics Foundation, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import socket +import sys + +import rclpy + +from libnmea_navsat_driver.driver import Ros2NMEADriver + +def main(args=None): + rclpy.init(args=args) + driver = Ros2NMEADriver() + + try: + gnss_ip = driver.declare_parameter('ip', '192.168.131.22').value + gnss_port = driver.declare_parameter('port', 9001).value + buffer_size = driver.declare_parameter('buffer_size', 4096).value + except KeyError as e: + driver.get_logger().err("Parameter %s not found" % e) + sys.exit(1) + + frame_id = driver.get_frame_id() + + driver.get_logger().info("Using gnss sensor with ip {} and port {}".format(gnss_ip, gnss_port)) + + # Connection-loop: connect and keep receiving. If receiving fails, reconnect + # Connect to the gnss sensor using tcp + while rclpy.ok(): + try: + # Create a socket + gnss_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # Connect to the gnss sensor + gnss_socket.connect((gnss_ip, gnss_port)) + except socket.error as exc: + driver.get_logger().error("Caught exception socket.error when setting up socket: %s" % exc) + sys.exit(1) + + # recv-loop: When we're connected, keep receiving stuff until that fails + partial = "" + while rclpy.ok(): + try: + partial += gnss_socket.recv(buffer_size).decode("ascii") + + # strip the data + lines = partial.splitlines() + if partial.endswith('\n'): + full_lines = lines + partial = "" + else: + full_lines = lines[:-1] + partial = lines[-1] + + for data in full_lines: + try: + if driver.add_sentence(data, frame_id): + driver.get_logger().info("Received sentence: %s" % data) + else: + driver.get_logger().warn("Error with sentence: %s" % data) + except ValueError as e: + driver.get_logger().warn( + "Value error, likely due to missing fields in the NMEA message. " + "Error was: %s. Please report this issue to me. " % e) + + except socket.error as exc: + driver.get_logger().error("Caught exception socket.error when receiving: %s" % exc) + gnss_socket.close() + break + + + gnss_socket.close() diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_topic_driver.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_topic_driver.py new file mode 100755 index 000000000..064071d9d --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_topic_driver.py @@ -0,0 +1,64 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2013, Eric Perko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the names of the authors nor the names of their +# affiliated organizations may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +from functools import partial + +from nmea_msgs.msg import Sentence +import rclpy + +from libnmea_navsat_driver.driver import Ros2NMEADriver + + +def nmea_sentence_callback(nmea_sentence, driver): + try: + driver.add_sentence(nmea_sentence.sentence, frame_id=nmea_sentence.header.frame_id, + timestamp=nmea_sentence.header.stamp) + except ValueError as e: + rclpy.get_logger().warn( + "Value error, likely due to missing fields in the NMEA message. Error was: %s. " + "Please report this issue at github.com/ros-drivers/nmea_navsat_driver, including a bag file with " + "the NMEA sentences that caused it." % e) + + +def main(args=None): + rclpy.init(args=args) + + driver = Ros2NMEADriver() + driver.get_frame_id() + + driver.create_subscription( + Sentence, 'nmea_sentence', partial(nmea_sentence_callback, driver=driver), 10) + + rclpy.spin(driver) + + rclpy.shutdown() diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_topic_serial_reader.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_topic_serial_reader.py new file mode 100755 index 000000000..fe5f702fd --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/nodes/nmea_topic_serial_reader.py @@ -0,0 +1,70 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2013, Eric Perko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the names of the authors nor the names of their +# affiliated organizations may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import serial + +from nmea_msgs.msg import Sentence +import rclpy + +from libnmea_navsat_driver.driver import Ros2NMEADriver + + +def main(args=None): + rclpy.init(args=args) + + driver = Ros2NMEADriver() + + nmea_pub = driver.create_publisher(Sentence, "nmea_sentence", 10) + + serial_port = driver.declare_parameter('port', '/dev/ttyUSB0').value + serial_baud = driver.declare_parameter('baud', 4800).value + + # Get the frame_id + frame_id = driver.get_frame_id() + + try: + GPS = serial.Serial(port=serial_port, baudrate=serial_baud, timeout=2) + try: + while rclpy.ok(): + data = GPS.readline().strip() + + sentence = Sentence() + sentence.header.stamp = driver.get_clock().now().to_msg() + sentence.header.frame_id = frame_id + sentence.sentence = data + nmea_pub.publish(sentence) + + except Exception as e: + driver.get_logger().error("Ros error: {0}".format(e)) + GPS.close() # Close GPS serial port + except serial.SerialException as ex: + driver.get_logger().fatal("Could not open serial port: I/O error({0}): {1}".format(ex.errno, ex.strerror)) diff --git a/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/parser.py b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/parser.py new file mode 100644 index 000000000..767e5183e --- /dev/null +++ b/src/interface/nmea_navsat_driver/src/libnmea_navsat_driver/parser.py @@ -0,0 +1,169 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2013, Eric Perko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the names of the authors nor the names of their +# affiliated organizations may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import re +import time +import calendar +import math +import logging + +logger = logging.getLogger('rosout') + + +def safe_float(field): + try: + return float(field) + except ValueError: + return float('NaN') + + +def safe_int(field): + try: + return int(field) + except ValueError: + return 0 + + +def convert_latitude(field): + return safe_float(field[0:2]) + safe_float(field[2:]) / 60.0 + + +def convert_longitude(field): + return safe_float(field[0:3]) + safe_float(field[3:]) / 60.0 + + +def convert_time(nmea_utc): + # Get current time in UTC for date information + utc_struct = time.gmtime() # immutable, so cannot modify this one + utc_list = list(utc_struct) + # If one of the time fields is empty, return NaN seconds + if not nmea_utc[0:2] or not nmea_utc[2:4] or not nmea_utc[4:6]: + return float('NaN') + else: + hours = int(nmea_utc[0:2]) + minutes = int(nmea_utc[2:4]) + seconds = int(nmea_utc[4:6]) + utc_list[3] = hours + utc_list[4] = minutes + utc_list[5] = seconds + unix_time = calendar.timegm(tuple(utc_list)) + return unix_time + + +def convert_status_flag(status_flag): + if status_flag == "A": + return True + elif status_flag == "V": + return False + else: + return False + + +def convert_knots_to_mps(knots): + return safe_float(knots) * 0.514444444444 + + +# Need this wrapper because math.radians doesn't auto convert inputs +def convert_deg_to_rads(degs): + return math.radians(safe_float(degs)) + + +"""Format for this dictionary is a sentence identifier (e.g. "GGA") as the key, with a +list of tuples where each tuple is a field name, conversion function and index +into the split sentence""" +parse_maps = { + "GGA": [ + ("fix_type", int, 6), + ("latitude", convert_latitude, 2), + ("latitude_direction", str, 3), + ("longitude", convert_longitude, 4), + ("longitude_direction", str, 5), + ("altitude", safe_float, 9), + ("mean_sea_level", safe_float, 11), + ("hdop", safe_float, 8), + ("num_satellites", safe_int, 7), + ("utc_time", convert_time, 1), + ], + "RMC": [ + ("utc_time", convert_time, 1), + ("fix_valid", convert_status_flag, 2), + ("latitude", convert_latitude, 3), + ("latitude_direction", str, 4), + ("longitude", convert_longitude, 5), + ("longitude_direction", str, 6), + ("speed", convert_knots_to_mps, 7), + ("true_course", convert_deg_to_rads, 8), + ], + "GST": [ + ("utc_time", convert_time, 1), + ("ranges_std_dev", safe_float, 2), + ("semi_major_ellipse_std_dev", safe_float, 3), + ("semi_minor_ellipse_std_dev", safe_float, 4), + ("semi_major_orientation", safe_float, 5), + ("lat_std_dev", safe_float, 6), + ("lon_std_dev", safe_float, 7), + ("alt_std_dev", safe_float, 8), + ], + "HDT": [ + ("heading", safe_float, 1), + ], + "VTG": [ + ("true_course", safe_float, 1), + ("speed", convert_knots_to_mps, 5) + ] +} + + +def parse_nmea_sentence(nmea_sentence): + # Check for a valid nmea sentence + + if not re.match(r'(^\$GP|^\$GN|^\$GL|^\$IN).*\*[0-9A-Fa-f]{2}$', nmea_sentence): + logger.debug("Regex didn't match, sentence not valid NMEA? Sentence was: %s" + % repr(nmea_sentence)) + return False + fields = [field.strip(',') for field in nmea_sentence.split(',')] + + # Ignore the $ and talker ID portions (e.g. GP) + sentence_type = fields[0][3:] + + if sentence_type not in parse_maps: + logger.debug("Sentence type %s not in parse map, ignoring." + % repr(sentence_type)) + return False + + parse_map = parse_maps[sentence_type] + + parsed_sentence = {} + for entry in parse_map: + parsed_sentence[entry[0]] = entry[1](fields[entry[2]]) + + return {sentence_type: parsed_sentence} diff --git a/src/interface/rosbridge_suite/.github/ISSUE_TEMPLATE.md b/src/interface/rosbridge_suite/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..0f5edeb48 --- /dev/null +++ b/src/interface/rosbridge_suite/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,22 @@ + + + + +## Expected Behavior + + +## Actual Behavior + + +## Steps to Reproduce the Problem + + 1. + 1. + 1. + +## Specifications + + - ROS Version (`echo $ROS_DISTRO`): + - OS Version (`grep DISTRIB_CODENAME /etc/lsb-release`): + - Rosbridge Version (`roscat rosbridge_server package.xml | grep ''`): + - Tornado Version (`python -c 'import tornado; print tornado.version'`): diff --git a/src/interface/rosbridge_suite/.github/dependabot.yml b/src/interface/rosbridge_suite/.github/dependabot.yml new file mode 100644 index 000000000..123014908 --- /dev/null +++ b/src/interface/rosbridge_suite/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" diff --git a/src/interface/rosbridge_suite/.github/workflows/ci.yml b/src/interface/rosbridge_suite/.github/workflows/ci.yml new file mode 100644 index 000000000..d6d841356 --- /dev/null +++ b/src/interface/rosbridge_suite/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: CI + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + + - uses: actions/setup-python@v4.5.0 + with: + python-version: '3.8' + + - uses: pre-commit/action@v3.0.0 + + test: + strategy: + fail-fast: false + matrix: + include: + # Test supported ROS 2 distributions + # https://docs.ros.org/en/rolling/Releases.html + - ros: foxy + os: ubuntu-20.04 + - ros: galactic + os: ubuntu-20.04 + - ros: humble + os: ubuntu-22.04 + - ros: rolling + os: ubuntu-22.04 + + name: ROS 2 ${{ matrix.ros }} (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v3 + with: + path: ros_ws/src + + - uses: ros-tooling/setup-ros@0.6.1 + + - uses: ros-tooling/action-ros-ci@v0.3 + with: + target-ros2-distro: ${{ matrix.ros }} diff --git a/src/interface/rosbridge_suite/.github/workflows/stale.yml b/src/interface/rosbridge_suite/.github/workflows/stale.yml new file mode 100644 index 000000000..d12e7c97f --- /dev/null +++ b/src/interface/rosbridge_suite/.github/workflows/stale.yml @@ -0,0 +1,25 @@ +name: Stale + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v7.0.0 + with: + stale-issue-message: "This issue has been marked as stale because there has been no activity in the past 12 months. Please add a comment to keep it open." + stale-issue-label: stale + days-before-issue-stale: 365 + days-before-issue-close: 30 + + stale-pr-message: "This PR has been marked as stale because there has been no activity in the past 6 months. Please add a comment to keep it open." + stale-pr-label: stale + days-before-pr-stale: 180 + days-before-pr-close: 30 + delete-branch: true diff --git a/src/interface/rosbridge_suite/.pre-commit-config.yaml b/src/interface/rosbridge_suite/.pre-commit-config.yaml new file mode 100644 index 000000000..9af419349 --- /dev/null +++ b/src/interface/rosbridge_suite/.pre-commit-config.yaml @@ -0,0 +1,42 @@ +# See https://pre-commit.com for more information +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.0.1 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-merge-conflict + - id: check-symlinks + - id: check-yaml + - id: debug-statements + - id: destroyed-symlinks + - id: detect-private-key + - id: end-of-file-fixer + - id: mixed-line-ending + - id: trailing-whitespace + + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + + - repo: https://github.com/psf/black + rev: 22.3.0 + hooks: + - id: black + + - repo: https://github.com/PyCQA/flake8 + rev: 3.9.2 + hooks: + - id: flake8 + + - repo: https://github.com/PyCQA/bandit + rev: 1.7.0 + hooks: + - id: bandit + args: ["--skip", "B101,B110,B311"] + + - repo: https://github.com/codespell-project/codespell + rev: v2.1.0 + hooks: + - id: codespell diff --git a/src/interface/rosbridge_suite/AUTHORS.md b/src/interface/rosbridge_suite/AUTHORS.md new file mode 100644 index 000000000..d94fccc78 --- /dev/null +++ b/src/interface/rosbridge_suite/AUTHORS.md @@ -0,0 +1,11 @@ +## Contributors + +- Brandon Alexander +- David Bertram +- Hans-Joachim Krauch +- Jacob Bandes-Storch +- Jihoon Lee +- Jonathan Mace +- Matthias Gruhler +- Russell Toris +- Travis Prosser diff --git a/src/msg/lgsvl_msgs/LICENSE b/src/interface/rosbridge_suite/LICENSE old mode 100755 new mode 100644 similarity index 59% rename from src/msg/lgsvl_msgs/LICENSE rename to src/interface/rosbridge_suite/LICENSE index 5cffa862d..5b627689a --- a/src/msg/lgsvl_msgs/LICENSE +++ b/src/interface/rosbridge_suite/LICENSE @@ -1,19 +1,20 @@ -Copyright (c) 2019-2020, LG Electronics -All rights reserved. +BSD 3-Clause License + +Copyright (c) The Rosbridge Authors Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. -* Neither the name of LG Electronics nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -24,4 +25,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/interface/rosbridge_suite/QUALITY_DECLARATION.md b/src/interface/rosbridge_suite/QUALITY_DECLARATION.md new file mode 100644 index 000000000..d7732d86c --- /dev/null +++ b/src/interface/rosbridge_suite/QUALITY_DECLARATION.md @@ -0,0 +1,78 @@ +This document is a declaration of software quality for the `rosbridge_suite` packages, based on the guidelines in [REP-2004](https://www.ros.org/reps/rep-2004.html). The following packages are covered by this declaration: + +- rosapi +- rosapi_msgs +- rosbridge_library +- rosbridge_msgs +- rosbridge_server +- rosbridge_suite +- rosbridge_test_msgs + +# `rosbridge_suite` Quality Declaration + +The package `rosbridge_suite` claims to be in the **Quality Level 3** category. + +Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Requirements for Quality Level N in REP-2004](https://www.ros.org/reps/rep-2004.html). + +## Version Policy [1] + +### Version Scheme [1.i] + +`rosbridge_suite` uses [semver](https://semver.org/) according to the recommendation in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#versioning). + +### Version Stability [1.ii] + +`rosbridge_suite` is at a stable version, i.e. `>= 1.0.0`. The current version can be found in its [package.xml](/rosbridge_server/package.xml), and its change history can be found in its [CHANGELOG](/rosbridge_server/CHANGELOG.rst). + +### Public API Declaration [1.iii] + +The public API is not explicitly defined. + +### API Stability Within a Released ROS Distribution [1.iv]/[1.vi] + +The public API is not guaranteed to be stable within a released ROS distribution. + +### ABI Stability Within a Released ROS Distribution [1.v]/[1.vi] + +`rosbridge_suite` is written in Python and therefore is not concerned with ABI stability. + +## Change Control Process [2] + +`rosbridge_suite` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process). + +### Change Requests [2.i] + +All changes will occur through a pull request, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information. + +### Continuous Integration [2.ii] + +All pull request must pass CI on all supported platforms. + +## Documentation [3] + +### License [3.i] + +The license for `rosbridge_suite` is BSD 3-clause, and a full copy is in the [LICENSE](/LICENSE) file. + +### Copyright Statement [3.ii] + +The copyright statement is in the [LICENSE](/LICENSE) file. + +## Testing [4] + +New features are required to have tests before being added. + +## Dependencies [5] + + +`rosbridge_suite` has a runtime dependency on `rclpy`, which does not have a quality declaration. + +## Platform Support [6] + +`rosbridge_suite` supports all of the tier 1 platforms as described in [REP-2000](https://www.ros.org/reps/rep-2000.html#support-tiers). Tests are currently only run against Ubuntu Linux. + +## Security [7] + +### Vulnerability Disclosure Policy [7.i] + +This package conforms to the Vulnerability Disclosure Policy in [REP-2006](https://www.ros.org/reps/rep-2006.html). diff --git a/src/interface/rosbridge_suite/README.md b/src/interface/rosbridge_suite/README.md new file mode 100644 index 000000000..d1117e494 --- /dev/null +++ b/src/interface/rosbridge_suite/README.md @@ -0,0 +1,62 @@ +rosbridge_suite +=============== + +[![ROS Foxy version](https://img.shields.io/ros/v/foxy/rosbridge_suite)](https://index.ros.org/p/rosbridge_suite/github-RobotWebTools-rosbridge_suite/#foxy) +[![ROS Galactic version](https://img.shields.io/ros/v/galactic/rosbridge_suite)](https://index.ros.org/p/rosbridge_suite/github-RobotWebTools-rosbridge_suite/#galactic) +[![ROS Humble version](https://img.shields.io/ros/v/humble/rosbridge_suite)](https://index.ros.org/p/rosbridge_suite/github-RobotWebTools-rosbridge_suite/#humble) +[![ROS Rolling version](https://img.shields.io/ros/v/rolling/rosbridge_suite)](https://index.ros.org/p/rosbridge_suite/github-RobotWebTools-rosbridge_suite/#rolling) + + +#### Server Implementations of the rosbridge v2 Protocol + +rosbridge provides a JSON interface to ROS, allowing any client to send JSON to publish or subscribe to ROS topics, call ROS services, and more. rosbridge supports a variety of transport layers, including WebSockets and TCP. For information on the protocol itself, see the [rosbridge protocol specification](ROSBRIDGE_PROTOCOL.md). + +For full documentation, see [the ROS wiki](http://ros.org/wiki/rosbridge_suite). + +This project is released as part of the [Robot Web Tools](http://robotwebtools.org/) effort. + +### Packages + + * [rosbridge_suite](rosbridge_suite) is a [ROS meta-package](http://www.ros.org/wiki/catkin/conceptual_overview#Metapackages_and_the_Elimination_of_Stacks) including all the rosbridge packages. + + * [rosbridge_library](rosbridge_library) contains the Python API that receives JSON-formatted strings as input and controls ROS publishers/subscribers/service calls according to the content of the JSON strings. + + * [rosbridge_server](rosbridge_server) contains a WebSocket server implementation that exposes the rosbridge_library. + + * [rosapi](rosapi) provides service calls for getting meta-information related to ROS like topic lists as well as interacting with the Parameter Server. + +### Clients + +A rosbridge client is a program that communicates with rosbridge using its JSON API. rosbridge clients include: + + * [roslibjs](https://github.com/RobotWebTools/roslibjs) - A JavaScript API, which communicates with rosbridge over WebSockets. + * [jrosbridge](https://github.com/WPI-RAIL/jrosbridge) - A Java API, which communicates with rosbridge over WebSockets. + * [roslibpy](https://github.com/gramaziokohler/roslibpy) - A Python API, which communicates with rosbridge over WebSockets. + * [roslibrust](https://github.com/Carter12s/roslibrust) - A Rust API, which communicates with rosbridge over WebSockets. + +### License +rosbridge_suite is released with a BSD license. For full terms and conditions, see the [LICENSE](LICENSE) file. + +### Authors +See the [AUTHORS](AUTHORS.md) file for a full list of contributors. + +### Quality Declaration +This package claims to be in the **Quality Level 3** category, see the [Quality Declaration](/QUALITY_DECLARATION.md) for more details. + +### Troubleshooting + +See the [TROUBLESHOOTING](TROUBLESHOOTING.md) doc for common problems and solutions. + +### Release process + +Releasing requires push access to [RobotWebTools/rosbridge_suite](https://github.com/RobotWebTools/rosbridge_suite) as well as [ros2-gbp/rosbridge_suite-release](https://github.com/ros2-gbp/rosbridge_suite-release). For more details on how the release process works, see the [bloom tutorial](https://docs.ros.org/en/galactic/How-To-Guides/Releasing-a-ROS-2-package-with-bloom.html). + +1. Run `catkin_generate_changelog` to update CHANGELOG.rst files. +2. Manually edit and clean up the changelogs. Commit the changes. +3. Run `catkin_prepare_release --bump [major/minor/patch]` to bump versions in package.xml and push changes to origin. +4. Run bloom-release commands to create PRs to update rosdistro: + - `bloom-release --rosdistro foxy --track foxy rosbridge_suite` + - `bloom-release --rosdistro galactic --track galactic rosbridge_suite` + - `bloom-release --rosdistro rolling --track rolling rosbridge_suite` + +Once the PRs are merged, packages will be available for each distro after the next sync. Build/sync status can be viewed at: [foxy](http://repo.ros2.org/status_page/ros_foxy_default.html), [galactic](http://repo.ros2.org/status_page/ros_galactic_default.html), [rolling](http://repo.ros2.org/status_page/ros_rolling_default.html). diff --git a/src/interface/rosbridge_suite/ROSBRIDGE_PROTOCOL.md b/src/interface/rosbridge_suite/ROSBRIDGE_PROTOCOL.md new file mode 100644 index 000000000..0d1b93758 --- /dev/null +++ b/src/interface/rosbridge_suite/ROSBRIDGE_PROTOCOL.md @@ -0,0 +1,507 @@ +# rosbridge v2.0 Protocol Specification + +> This document describes the ROS 2 version of rosbridge. For ROS 1, please see the [ros1 branch](https://github.com/RobotWebTools/rosbridge_suite/blob/ros1/ROSBRIDGE_PROTOCOL.md). + +This document outlines the rosbridge v2.0 protocol. The v2.0 protocol +incorporates a number of requirements which have arisen since the first version +of rosbridge was released, and makes a small number of modifications to +facilitate greater extensibility to the protocol. At its core, the protocol +still contains the same operations with the same semantics as the prior +versions of rosbridge. The main change is to the structure of messages, +separating control information from message information. The main new additions +are fragmentation, compression, and logging. + +This document outlines the protocol specification, but also touches upon the +intended direction for the rosbridge server implementation. The rosbridge v2.0 +server implementation is architected in a way to make it easy to add and modify +protocol operations. Furthermore, the rosbridge v2.0 server decouples +JSON-handling from the websockets server, allowing users to arbitrarily change +the specific websockets server implementation they are using. + +The message transport of rosbridge is JSON objects. The only required field is +the 'op' field, which specifies the operation of that message. Each 'op' then +specifies its own message semantics. + +The rosbridge protocol is a set of 'op' codes which define a number of +operations, along with the semantics for each operation. + +The rosbridge server is a server which accepts websockets connections and +implements the rosbridge protocol. + +The full source code of rosbridge is located in the rosbridge_suite package. +The package is located at https://github.com/robotwebtools/rosbridge_suite, and +the full breakdown of the stack and its packages is detailed in section 4.5 of +this document. + +## 1. The rosbridge transport + +A rosbridge message is, in the base case, a JSON object with a string field +called "op". For example: + +```json +{ "op": "Example" } +``` + +The op field indicates the type of message that this is. Messages with +different values for op may be handled differently. + +So long as the message is a JSON object with the op field, it is a valid +rosbridge message. + +Optionally, a message can also provide an arbitrary string or integer ID: + +```json +{ "op": "Example", + "id":"fred" +} +``` + +If an ID is provided with a message to the server, then related response +messages will typically contain that ID as well. Log messages caused by this +operation will also contain the ID. + +Semantically, the ID is not an identifier of the specific message that it is +in, but instead is an identifier for an interaction which may consist of a +number of operations in back-and-forth messages. Thus, the ID may be used by +multiple messages referring to the same transaction. + +## 2. The rosbridge protocol + +The rosbridge protocol defines a number of different operations. They are as follows: + +Message compression / transformation: + + * **fragment** - a part of a fragmented message + * **png** - a part of a PNG compressed fragmented message + +Rosbridge status messages: + + * **set_status_level** - a request to set the reporting level for rosbridge status messages + * **status** - a status message + +ROS operations: + + * **advertise** – advertise that you are publishing a topic + * **unadvertise** – stop advertising that you are publishing topic + * **publish** - a published ROS-message + * **subscribe** - a request to subscribe to a topic + * **unsubscribe** - a request to unsubscribe from a topic + * **call_service** - a service call + * **advertise_service** - advertise an external service server + * **unadvertise_service** - unadvertise an external service server + * **service_request** - a service request + * **service_response** - a service response + +In general, actions or operations that the client takes (such as publishing and +subscribing) have opcodes which are verbs (subscribe, call_service, unadvertise +etc.). + +Response messages from the server are things that the client is giving back, so +they are nouns (fragment, status, service_response etc.) + +(The only slight exception to this naming convention is publish) + +## 3. Details of the rosbridge protocol + +Following is the specification of operations in the rosbridge protocol, +supported by the rosbridge server. Anything marked with [experimental] may be +subject to change after review. + +### 3.1 Data Encoding and Transformation + +The rosbridge protocol provides the ability to fragment messages and to compress messages. + +#### 3.1.1 Fragmentation ( _fragment_ ) [experimental] + +Messages may be fragmented if they are particularly large, or if the client +requests fragmentation. A fragmented message has the following format: + +```json +{ "op": "fragment", + "id": , + "data": , + "num": , + "total": +} +``` + +**id** - an id is required for fragmented messages, in order to identify +corresponding fragments for the fragmented message: + + * **data** - a fragment of data that, when combined with other fragments of data, makes up another message + * **num** - the index of the fragment in the message + * **total** - the total number of fragments + +To fragment a message, its JSON string is taken and split up into multiple +substrings. For each substring, a fragment message is constructed, with the +data field of the fragment populated by the substring. + +To reconstruct an original message, the data fields of the fragments are +concatenated, resulting in the JSON string of the original message. + +#### 3.1.2 PNG compression ( _png_ ) [experimental] + +Some messages (such as images and maps) can be extremely large, and for efficiency +reasons we may wish to transfer them as PNG-encoded bytes. The PNG opcode +duplicates the fragmentation logic of the FRG opcode (and it is possible and +reasonable to only have a single fragment), except that the data field consists +of ASCII-encoded PNG bytes. + +```json +{ "op": "png", + (optional) "id": , + "data": , + (optional) "num": , + (optional) "total": +} +``` + + * **id** – only required if the message is fragmented. Identifies the + fragments for the fragmented message. + * **data** – a fragment of a PNG-encoded message or an entire message. + * **num** – only required if the message is fragmented. The index of the fragment. + * **total** – only required if the message is fragmented. The total number of fragments. + +To construct a PNG compressed message, take the JSON string of the original +message and read the bytes of the string into a PNG image. Then, ASCII-encode +the image. This string is now used as the data field. If fragmentation is +necessary, then fragment the data and set the ID, num and total fields to the +appropriate values in the fragments. Otherwise these fields can be left out. + +#### 3.1.3 CBOR encoding ( _cbor_ ) + +[CBOR](https://tools.ietf.org/html/rfc7049) encoding is the fastest +compression method for messages containing large blobs of data, such as +byte arrays and numeric typed arrays. + +When CBOR compression is requested by a subscriber, a binary message will be +produced instead of a JSON string. Once decoded, the message will contain +a normal protocol message. + +The implementation uses [draft typed array tags] for efficient packing of +homogeneous arrays. At the moment, only little-endian packing is supported. + +[draft typed array tags]: https://tools.ietf.org/html/draft-ietf-cbor-array-tags-00 + +#### 3.1.4 CBOR-RAW encoding ( _cbor-raw_ ) + +While CBOR encodes the entire message as CBOR, sometimes it's desirable to get the raw binary message in the +[ROS serialization format](https://wiki.ros.org/roscpp/Overview/MessagesSerializationAndAdaptingTypes), +which is the same format as sent between ROS nodes and stored in [Bag files](http://wiki.ros.org/Bags/Format/2.0). + +This can be useful in several cases: +- Your application already knows how to parse messages in bag files (e.g. using + [rosbag.js](https://github.com/cruise-automation/rosbag.js), which means that now you can use + consistent code paths for both bags and live messages. +- You want to parse messages as late as possible, or in parallel, e.g. only in the thread + or WebWorker that cares about the message. Delaying the parsing of the message means that moving + or copying the message to the thread is cheaper when its in binary form, since no serialization + between threads is necessary. +- You only care about part of the message, and don't need to parse the rest of it. +- You really care about performance; no conversion between the ROS binary format and CBOR is done in + the rosbridge_sever. + +The format is similar to CBOR above, but instead of the "msg" field containing the message itself +in CBOR format, instead it contains an object with a "bytes" field which is a byte array containing +the raw message. The "msg" object also includes "secs" and "nsecs" of the `get_rostime()` upon +receiving the message, which is especially useful when `use_sim_time` is set, since it will give you +the simulated time the message was received. + +When using this encoding, a client application will need to know exactly how to parse the raw +message. For this it's useful to use the `/rosapi/get_topics_and_raw_types` service, which will give +you all topics and their raw message definitions, similar to `gendeps --cat`. This is the same +format as used by bag files. + +### 3.2 Status messages + +rosbridge sends status messages to the client relating to the successes and +failures of rosbridge protocol commands. There are four status levels: info, +warning, error, none. By default, rosbridge uses a status level of error. + +A rough guide for what causes the levels of status message: + + * **error** – Whenever a user sends a message that is invalid or requests + something that does not exist (ie. Sending an incorrect opcode or publishing + to a topic that doesn't exist) + * **warning** – error, plus, whenever a user does something that may succeed + but the user has still done something incorrectly (ie. Providing a + partially-complete published message) + * **info** – warning, plus messages indicating success of various operations + +#### 3.2.1 Set Status Level ( _status_level_ ) [experimental] + +```json +{ "op": "set_level", + (optional) "id": , + "level": +} +``` + + * **level** – one of 'info', 'warning', 'error', or 'none' + +Sets the status level to the level specified. If a bad string is specified, the +message is dropped. + +#### 3.2.2 Status message ( _status_ ) [experimental] + +```json +{ "op": "status", + (optional) "id": , + "level": , + "msg": +} +``` + + * **level** – the level of this status message + * **msg** – the string message being logged + * **id** – if the status message was the result of some operation that had an + id, then that id is included + +### 3.3 ROS messages + +These rosbridge messages interact with ROS, and correspond roughly to the +messages that already exist in the current version of rosbridge. + +#### 3.3.1 Advertise ( _advertise_ ) + +If you wish to advertise that you are or will be publishing a topic, then use +the advertise command. + +```json +{ "op": "advertise", + (optional) "id": , + "topic": , + "type": +} +``` + + * **topic** – the string name of the topic to advertise + * **type** – the string type to advertise for the topic + + * If the topic does not already exist, and the type specified is a valid + type, then the topic will be established with this type. + * If the topic already exists with a different type, an error status message + is sent and this message is dropped. + * If the topic already exists with the same type, the sender of this message + is registered as another publisher. + * If the topic doesn't already exist but the type cannot be resolved, then + an error status message is sent and this message is dropped. + +#### 3.3.2 Unadvertise ( _unadvertise_ ) + +This stops advertising that you are publishing a topic. + +```json +{ "op": "unadvertise", + (optional) "id": , + "topic": +} +``` + + * **topic** – the string name of the topic being unadvertised + + * If the topic does not exist, a warning status message is sent and this + message is dropped + * If the topic exists and there are still clients left advertising it, + rosbridge will continue to advertise it until all of them have unadvertised + * If the topic exists but rosbridge is not advertising it, a warning status + message is sent and this message is dropped + +#### 3.3.3 Publish ( _publish_ ) + +The publish message is used to send data on a topic. + +```json +{ "op": "publish", + (optional) "id": , + "topic": , + "msg": +} +``` + +The publish command publishes a message on a topic. + + * **topic** - the string name of the topic to publish to + * **msg** - the message to publish on the topic + + * If the topic does not exist, then an error status message is sent and this + message is dropped + * If the msg does not conform to the type of the topic, then an error status + message is sent and this message is dropped + * If the msg is a subset of the type of the topic, then a warning status + message is sent and the unspecified fields are filled in with defaults + +Special case: if the type being published has a 'header' field, then the client +can optionally omit the header from the msg. If this happens, rosbridge will +automatically populate the header with a frame id of "" and the timestamp as +the current time. Alternatively, just the timestamp field can be omitted, and +then the current time will be automatically inserted. + +#### 3.3.4 Subscribe + +```json +{ "op": "subscribe", + (optional) "id": , + "topic": , + (optional) "type": , + (optional) "throttle_rate": , + (optional) "queue_length": , + (optional) "fragment_size": , + (optional) "compression": +} +``` + +This command subscribes the client to the specified topic. It is recommended +that if the client has multiple components subscribing to the same topic, that +each component makes its own subscription request providing an ID. That way, +each can individually unsubscribe and rosbridge can select the correct rate at +which to send messages. + + * **type** – the (expected) type of the topic to subscribe to. If left off, + type will be inferred, and if the topic doesn't exist then the command to + subscribe will fail + * **topic** – the name of the topic to subscribe to + * **throttle_rate** – the minimum amount of time (in ms) that must elapse + between messages being sent. Defaults to 0 + * **queue_length** – the size of the queue to buffer messages. Messages are + buffered as a result of the throttle_rate. Defaults to 0 (no queueing). + * **id** – if specified, then this specific subscription can be unsubscribed + by referencing the ID. + * **fragment_size** – the maximum size that a message can take before it is to + be fragmented. + * **compression** – an optional string to specify the compression scheme to be + used on messages. Valid values are "none", "png", "cbor", and "cbor-raw". + +If queue_length is specified, then messages are placed into the queue before +being sent. Messages are sent from the head of the queue. If the queue gets +full, the oldest message is removed and replaced by the newest message. + +If a client has multiple subscriptions to the same topic, then messages are +sent at the lowest throttle_rate, with the lowest fragmentation size, and +highest queue_length. It is recommended that the client provides IDs for its +subscriptions, to enable rosbridge to effectively choose the appropriate +fragmentation size and publishing rate. + +#### 3.3.5 Unsubscribe + +```json +{ "op": "unsubscribe", + (optional) "id": , + "topic": +} +``` + + * **topic** – the name of the topic to unsubscribe from + * **id** – an id of the subscription to unsubscribe + +If an id is provided, then only the corresponding subscription is unsubscribed. +If no ID is provided, then all subscriptions are unsubscribed. + +#### 3.3.6 Call Service + +```json +{ "op": "call_service", + (optional) "id": , + "service": , + (optional) "args": >, + (optional) "fragment_size": , + (optional) "compression": +} +``` + +Calls a ROS service + + * **service** – the name of the service to call + * **args** – if the service has no args, then args does not have to be + provided, though an empty list is equally acceptable. Args should be a list + of json objects representing the arguments to the service + * **id** – an optional id to distinguish this service call + * **fragment_size** – the maximum size that the response message can take + before it is fragmented + * **compression** – an optional string to specify the compression scheme to be + used on messages. Valid values are "none" and "png" + +#### 3.3.7 Advertise Service + +```json +{ "op": "advertise_service", + "type": , + "service": +} +``` + +Advertises an external ROS service server. Requests come to the client via Call Service. + + * **service** – the name of the service to advertise + * **type** – the advertised service message type + +#### 3.3.8 Unadvertise Service + +```json +{ "op": "unadvertise_service", + "service": +} +``` + +Stops advertising an external ROS service server + + * **service** – the name of the service to unadvertise + +#### 3.3.9 Service Response + +```json +{ "op": "service_response", + (optional) "id": , + "service": , + (optional) "values": >, + "result": +} +``` + +A response to a ROS service call + + * **service** – the name of the service that was called + * **values** – the return values. If the service had no return values, then + this field can be omitted (and will be by the rosbridge server) + * **id** – if an ID was provided to the service request, then the service + response will contain the ID + * **result** - return value of service callback. true means success, false failure. + +## 4 Further considerations + +Further considerations for the rosbridge protocol are listed below. + +### 4.1 Rosbridge psuedo-services + +Rosbridge no longer provides the ROS-api introspection pseudo services that it +previously did. These are, for example rosbridge/topics and rosbridge/services. +Instead, these services are provided as proper ROS services by the new rosapi +package. + +### 4.2 Sampling + +It has been suggested that rosbridge may be extended to provide an operation to +sample a single message from a topic. + +### 4.3 Latching + +Rosbridge will support messages that were latched to topics internally in ROS. +It is possible that the publish opcode will be extended so that remote clients +can latch messages too. + +### 4.5 Rosbridge package structure + +Rosbridge 2.0 resides in a package named rosbridge_suite, located at +https://github.com/robotwebtools/rosbridge_suite. + +The meta-package will contain the following packages: + + * **rosbridge_library** – the core rosbridge JSON-to-ROS implementation. This + is be a Python library. + * **rosbridge_server** – depends on the rosbridge library, and implements the + WebSockets server, passing incoming messages to the API and outgoing + messages back to the WebSockets connection. The default server uses + tornado, a python server implementation. + * **rosapi** – provides ROS services for various master API calls, such as + listing all the topics, services, types currently in ROS + diff --git a/src/interface/rosbridge_suite/TROUBLESHOOTING.md b/src/interface/rosbridge_suite/TROUBLESHOOTING.md new file mode 100644 index 000000000..1900068f5 --- /dev/null +++ b/src/interface/rosbridge_suite/TROUBLESHOOTING.md @@ -0,0 +1,27 @@ +### Tornado Version + +Often the server breaks because it is using the wrong version of Tornado. Tornado's interfaces and behavior change very quickly, Rosbridge is only tested against the version installed by rosdep. On Debian-based systems, this is the apt package python-tornado. + +To check your imported Tornado version, run: + +``` +python -c 'import tornado; print tornado.version' +``` + +The imported version should the `apt` version: + +``` +apt-cache show python-tornado | grep Version +``` + +If the versions don't match, it's likely that the wrong version of Tornado was installed with `pip`. Try uninstalling it: + +``` +pip uninstall tornado +``` + +If the wrong version is still imported, you will need to find it and remove it. You might find it with something like: + +``` +find /usr/local/lib/python*/*-packages/ -type d | grep '/tornado/' +``` diff --git a/src/interface/rosbridge_suite/pyproject.toml b/src/interface/rosbridge_suite/pyproject.toml new file mode 100644 index 000000000..2ebe07a83 --- /dev/null +++ b/src/interface/rosbridge_suite/pyproject.toml @@ -0,0 +1,5 @@ +[tool.bandit] +skips = ["B101", "B110", "B311"] + +[tool.black] +line-length = 100 diff --git a/src/interface/rosbridge_suite/rosapi/CHANGELOG.rst b/src/interface/rosbridge_suite/rosapi/CHANGELOG.rst new file mode 100644 index 000000000..10e36faa6 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/CHANGELOG.rst @@ -0,0 +1,370 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosapi +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.3.1 (2022-10-21) +------------------ +* Add graceful shutdown (`#794 `_) +* Contributors: Hans-Joachim Krauch + +1.3.0 (2022-08-16) +------------------ +* Fixed /get_param service for arrays (`#776 `_) +* Contributors: p0rys + +1.2.0 (2022-05-20) +------------------ +* Added `/rosapi/get_ros_version` service (`#708 `_) +* Fixed node name collision with websocket launch file (`#707 `_) +* Contributors: Jacob Bandes-Storch, Kedus Mathewos, rob-clarke + +1.1.2 (2022-01-03) +------------------ + +1.1.1 (2021-12-09) +------------------ + +1.1.0 (2021-10-22) +------------------ +* Move msg/srv from rosapi and rosbridge_library into separate packages; enable Rolling in CI (`#665 `_) +* Exit cleanly on SIGINT; remove sleep in test (`#667 `_) +* Remove unused service_host and search_param services (`#660 `_) +* Migrate remaining linters to pre-commit (`#657 `_) +* Add pre-commit, format with black and isort (`#648 `_) +* Contributors: Adrian Macneil, Jacob Bandes-Storch, Kenji Miyake + +1.0.8 (2021-08-26) +------------------ +* Add missing test_depends and buildtool_depends (`#617 `_) +* Fix various Python code style and lint issues +* Contributors: Christian Clauss, Jacob Bandes-Storch + +1.0.7 (2021-08-18) +------------------ +* Load message definitions from .msg files; exclude /msg/ and include builtin_interfaces in combined definitions (`#597 `_) +* Fix typos discovered by codespell (`#600 `_) +* Contributors: Christian Clauss, Jacob Bandes-Storch + +1.0.6 (2021-08-17) +------------------ +* Include /msg/ in type names (`#591 `_) +* Fix broken links in changelogs +* Contributors: Jacob Bandes-Storch + +1.0.5 (2021-08-12) +------------------ + +1.0.4 (2021-08-11) +------------------ +* Include /msg/ in type names (`#584 `_) + It's more canonical for ROS 2 type names to be of the form `foo_msgs/msg/Bar` rather than just `foo_msgs/Bar`. This is occasionally reflected in documentation and command line tooling: https://docs.ros.org/en/galactic/Tutorials/Topics/Understanding-ROS2-Topics.html#ros2-interface-show + So rather than stripping out `/msg/`, we include it in the type definitions. + See also: https://github.com/RobotWebTools/rosmsg/pull/12 +* Contributors: Jacob Bandes-Storch + +1.0.3 (2021-08-03) +------------------ +* Add TopicsAndRawTypes service (`#574 `_, adapted from ROS 1 implementation `#452 `_) +* fix: remove json encoding before setting string params (`#521 `_) +* Update rosapi/proxy.py to match eloquent API (`#447 `_) +* Contributors: Jacob Bandes-Storch, justinscorringe, travipross + +1.0.2 (2019-09-24) +------------------ + +1.0.1 (2019-09-20) +------------------ +* fix missing dependency + +1.0.0 (2019-09-19) +------------------ +* Port to ROS 2 + +0.11.3 (2019-08-07) +------------------- +* Travis CI: Look for Python syntax errors and undefined name (`#420 `_) + * Travis CI: Look for Python syntax errors and undefined name + _It would be prudent to start running the tests in both 2 and 3._ https://github.com/RobotWebTools/rosbridge_suite/issues/401#issuecomment-512069249 + * Add names to protect the guilty + * Five jobs, not six + * Identity is not the same thing as equality in Python + * Flake8 tests now pass on Python 2 +* Contributors: cclauss + +0.11.2 (2019-07-08) +------------------- +* constnames and constvalues in typedef (`#412 `_) +* Contributors: Kad91 + +0.11.1 (2019-05-08) +------------------- + +0.11.0 (2019-03-29) +------------------- + +0.10.2 (2019-03-04) +------------------- +* Use Master.getTopicTypes() in /rosapi/topics to increase performance (`#381 `_) +* Contributors: Affonso, Guilherme + +0.10.1 (2018-12-16) +------------------- + +0.10.0 (2018-12-14) +------------------- +* Drop use of ros Python module (`#374 `_) +* Fixes passing of globs to proxy (`#355 `_) + * Fixes handling and passing of globs to proxy + * Removes some confusing imports +* Fix a few problems (`#350 `_) + * xrange is not available in Python3, range works for both Python versions + * the variable v is undefined in search_param, comparing the implementation with the sibling functions I expect name to be the intended variable + * The module udp_handler is using the Authentication service but wasn't importing the module +* use package format 2, remove unnecessary dependencies (`#348 `_) +* Contributors: Anwar, Dirk Thomas, Jochen Sprickerhof + +0.9.0 (2018-04-09) +------------------ + +0.8.6 (2017-12-08) +------------------ +* Fixed action_servers filter to allow more than one namespace (`#305 `_) + * Modified action_servers filter to detect topics with more than one namespace + * Fixed to return the full namespace +* Contributors: milesial + +0.8.5 (2017-11-23) +------------------ +* Add Python3 compatibility (`#300 `_) + * First pass at Python 3 compatibility + * message_conversion: Only call encode on a Python2 str or bytes type + * protocol.py: Changes for dict in Python3. Compatible with Python 2 too. + * More Python 3 fixes, all tests pass + * Move definition of string_types to rosbridge_library.util +* Contributors: Kartik Mohta + +0.8.4 (2017-10-16) +------------------ +* Handles empty globes properly (`#297 `_) + * Refactors get_globs function to a separate module + * Refactors the filtering that uses the globs + * Some linting + * Handles topic types for empty globs + * Refactors out an any_match function + * Simplifies filter_action_servers + * Imports socket for the errors + * Uses import .glob_helper +* Contributors: Anwar + +0.8.3 (2017-09-11) +------------------ + +0.8.2 (2017-09-11) +------------------ +* Removes array delimiters while parsing parameters (`#292 `_) +* Contributors: Anwar + +0.8.1 (2017-08-30) +------------------ + +0.8.0 (2017-08-30) +------------------ +* fix delete_param in rosapi (`#284 `_) +* Merge pull request `#276 `_ from sevenbitbyte/DOCUMENT_GLOB + Document glob +* Update README.md + Formatting and examples +* Create README.md +* Contributors: 7bit, Jihoon Lee + +0.7.17 (2017-01-25) +------------------- +* Added bug fix in rosapi +* no rospy needed, just for debug logging +* new service: get actionlib servers +* adjust log level for security globs + Normal operation (i.e. no globs or successful verification of requests) is now silent, with illegal requests producing a warning. +* correct default values for security globs + also accept empty list as the default "do not check globs" value in addition to None. + Finally, append rosapi service glob after processing command line input so it's not overwritten +* Added services_glob to CallServices, added globs to rosbridge_tcp and rosbridge_udp, and other miscellaneous fixes. +* As per the suggestions of @T045T, fixed several typos, improved logging, and made some style fixes. +* Fixed time object field definitions to match documentation. +* Two minor fixes. +* Added new parameters for topic and service security. + Added 3 new parameters to rosapi and rosbridge_server which filter the + topics, services, and parameters broadcast by the server to match an + array of glob strings. +* Contributors: Devon Ash, Eric, Marco Arruda, Nils Berg + +0.7.16 (2016-08-15) +------------------- +* new srv: topics types and details +* Contributors: Marco Arruda + +0.7.15 (2016-04-25) +------------------- +* changelog updated +* Contributors: Russell Toris + +0.7.14 (2016-02-11) +------------------- +* Update proxy.py + Fixes an issue when call the service "/rosapi/service_type" +* Contributors: Robert Codd-Downey + +0.7.13 (2015-08-14) +------------------- +* Fix catkin_lint issues +* Contributors: Matt Vollrath + +0.7.12 (2015-04-07) +------------------- + +0.7.11 (2015-03-23) +------------------- +* rename rosapi script to rosapi_node to address `#170 `_ +* Contributors: Jihoon Lee + +0.7.10 (2015-02-25) +------------------- +* Make get_topics() and get_topic_type() reference the full list of active topics. +* Contributors: Justin Huang + +0.7.9 (2015-02-24) +------------------ +* add findding service function as specific service type +* Contributors: dwlee + +0.7.8 (2015-01-16) +------------------ + +0.7.7 (2015-01-06) +------------------ + +0.7.6 (2014-12-26) +------------------ +* 0.7.5 +* update changelog +* 0.7.4 +* changelog updated +* 0.7.3 +* changelog updated +* 0.7.2 +* changelog updated +* 0.7.1 +* update changelog +* 0.7.0 +* changelog updated +* Contributors: Jihoon Lee, Russell Toris + +0.7.5 (2014-12-26) +------------------ + +0.7.4 (2014-12-16) +------------------ + +0.7.3 (2014-12-15) +------------------ + +0.7.2 (2014-12-15) +------------------ +* 0.7.1 +* update changelog +* Contributors: Jihoon Lee + +0.7.1 (2014-12-09) +------------------ + +0.7.0 (2014-12-02) +------------------ + +0.6.8 (2014-11-05) +------------------ + +0.6.7 (2014-10-22) +------------------ +* updated package manifests +* Contributors: Russell Toris + +0.6.6 (2014-10-21) +------------------ + +0.6.5 (2014-10-14) +------------------ +* 0.6.4 +* update changelog +* 0.6.3 +* update change log +* Contributors: Jihoon Lee + +0.6.4 (2014-10-08) +------------------ + +0.6.3 (2014-10-07) +------------------ + +0.6.2 (2014-10-06) +------------------ + +0.6.1 (2014-09-01) +------------------ +* make rosapis use absolute namespace +* Contributors: Jihoon Lee + +0.6.0 (2014-05-23) +------------------ +* Ensure proper locking for Parameter Server access +* Contributors: Lasse Rasinen + +0.5.4 (2014-04-17) +------------------ +* add rosnode and rosgraph +* Contributors: Jihoon Lee + +0.5.3 (2014-03-28) +------------------ + +0.5.2 (2014-03-14) +------------------ + +0.5.1 (2013-10-31) +------------------ + +0.5.0 (2013-07-17) +------------------ +* 0.5.0 preparation for hydro release +* Removes trailing commas. +* removing global bin installation in setup.py +* Contributors: Brandon Alexander, Jihoon Lee + +0.4.4 (2013-04-08) +------------------ + +0.4.3 (2013-04-03 08:24) +------------------------ + +0.4.2 (2013-04-03 08:12) +------------------------ +* eclipse projects removed +* Contributors: Russell Toris + +0.4.1 (2013-03-07) +------------------ +* fixes import issue in rosapi +* Contributors: Russell Toris + +0.4.0 (2013-03-05) +------------------ +* Fixes ambiguous params class reference. +* Uses only 1 .gitignore to avoid confusion. +* Fixing rosapi's "Cannot include proxy..." errors. +* Adds BSD license header to code files. + See Issue `#13 `_. +* rosbridge_server requires rosapi. +* Adds message and service generation to rosapi. +* Adding setup.py to rosapi. +* Clarifies name of rosapi is rosapi. +* Catkinizes rosapi. +* Collapse directory structure. +* Contributors: Austin Hendrix, Brandon Alexander diff --git a/src/interface/rosbridge_suite/rosapi/CMakeLists.txt b/src/interface/rosbridge_suite/rosapi/CMakeLists.txt new file mode 100644 index 000000000..1f41d5e42 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.5) +project(rosapi) + +find_package(ament_cmake_ros REQUIRED) + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +ament_python_install_package( + ${PROJECT_NAME} PACKAGE_DIR "src/${PROJECT_NAME}") + +ament_package() + +install(PROGRAMS scripts/rosapi_node + DESTINATION lib/${PROJECT_NAME} +) + +install( + FILES mapping_rules.yaml + DESTINATION share/${PROJECT_NAME} +) + +if(BUILD_TESTING) + find_package(ament_cmake_pytest REQUIRED) + ament_add_pytest_test(${PROJECT_NAME}_test_stringify_field_types test/test_stringify_field_types.py) +endif() diff --git a/src/interface/rosbridge_suite/rosapi/README.md b/src/interface/rosbridge_suite/rosapi/README.md new file mode 100644 index 000000000..1244fc675 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/README.md @@ -0,0 +1,29 @@ +rosapi +=============== + +#### Parameters + + * `~topics_glob` (string, default '') + * `~services_glob` (string, default '') + * `~params_glob` (string, default '') + + ```Note: By default the rosapi calls for details about topics, services, and parameters will return nothing. You must specify a list of allowed resources.``` + Each of the glob parameters may contain an array of one or more match patterns. Resources that match any of the specified patterns will be returned by calls to the rosapi services. + +An example launch file which enables all information to be returned. + +``` + + + + + +``` + + +This example launch file enables only rosout and certain camera topics +``` + + + +``` diff --git a/src/interface/rosbridge_suite/rosapi/mapping_rules.yaml b/src/interface/rosbridge_suite/rosapi/mapping_rules.yaml new file mode 100644 index 000000000..ae367c8a1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/mapping_rules.yaml @@ -0,0 +1,8 @@ +- + ros1_package_name: 'rosapi' + ros1_service_name: 'GetParam' + ros2_package_name: 'rosapi' + ros2_service_name: 'GetParam' + request_fields_1_to_2: + name: 'name' + default: 'default_value' diff --git a/src/interface/rosbridge_suite/rosapi/package.xml b/src/interface/rosbridge_suite/rosapi/package.xml new file mode 100644 index 000000000..0071c9f0c --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/package.xml @@ -0,0 +1,47 @@ + + + rosapi + 1.3.1 + + Provides service calls for getting ros meta-information, like list of + topics, services, params, etc. + + + BSD + + http://ros.org/wiki/rosapi + https://github.com/RobotWebTools/rosbridge_suite/issues + https://github.com/RobotWebTools/rosbridge_suite + + Jonathan Mace + Jihoon Lee + Foxglove + + ament_cmake_ros + + rosapi_msgs + builtin_interfaces + rclpy + rcl_interfaces + rosbridge_library + ros2node + ros2param + ros2pkg + ros2service + ros2topic + + + ament_cmake_pytest + sensor_msgs + shape_msgs + geometry_msgs + rmw_dds_common + + + ament_cmake + + + diff --git a/src/interface/rosbridge_suite/rosapi/scripts/rosapi_node b/src/interface/rosbridge_suite/rosapi/scripts/rosapi_node new file mode 100755 index 000000000..af478ee52 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/scripts/rosapi_node @@ -0,0 +1,329 @@ +#!/usr/bin/env python3 +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import os +import sys + +import rclpy +from rclpy.clock import Clock, ClockType +from rclpy.node import Node + +from rosapi import glob_helper, objectutils, params, proxy +from rosapi_msgs.msg import TypeDef +from rosapi_msgs.srv import ( + DeleteParam, + GetActionServers, + GetParam, + GetParamNames, + GetROSVersion, + GetTime, + HasParam, + MessageDetails, + NodeDetails, + Nodes, + Publishers, + ServiceNode, + ServiceProviders, + ServiceRequestDetails, + ServiceResponseDetails, + Services, + ServicesForType, + ServiceType, + SetParam, + Subscribers, + Topics, + TopicsAndRawTypes, + TopicsForType, + TopicType, +) + + +class Rosapi(Node): + + NAME = "rosapi" + + def __init__(self): + super().__init__(self.NAME) + self.declare_parameter("topics_glob", "[*]") + self.declare_parameter("services_glob", "[*]") + self.declare_parameter("params_glob", "[*]") + self.globs = self.get_globs() + self.register_services() + + # Initialises the ROS node + def register_services(self): + proxy.init(self) + if self.get_namespace() == "/": + full_name = self.get_namespace() + self.get_name() + else: + full_name = self.get_namespace() + "/" + self.get_name() + params.init(full_name) + self.create_service(Topics, "/rosapi/topics", self.get_topics) + self.create_service(TopicsForType, "/rosapi/topics_for_type", self.get_topics_for_type) + self.create_service( + TopicsAndRawTypes, + "/rosapi/topics_and_raw_types", + self.get_topics_and_raw_types, + ) + self.create_service(Services, "/rosapi/services", self.get_services) + self.create_service( + ServicesForType, "/rosapi/services_for_type", self.get_services_for_type + ) + self.create_service(Nodes, "/rosapi/nodes", self.get_nodes) + self.create_service(NodeDetails, "/rosapi/node_details", self.get_node_details) + self.create_service(GetActionServers, "/rosapi/action_servers", self.get_action_servers) + self.create_service(TopicType, "/rosapi/topic_type", self.get_topic_type) + self.create_service(ServiceType, "/rosapi/service_type", self.get_service_type) + self.create_service(Publishers, "/rosapi/publishers", self.get_publishers) + self.create_service(Subscribers, "/rosapi/subscribers", self.get_subscribers) + self.create_service( + ServiceProviders, "/rosapi/service_providers", self.get_service_providers + ) + self.create_service(ServiceNode, "/rosapi/service_node", self.get_service_node) + self.create_service(MessageDetails, "/rosapi/message_details", self.get_message_details) + self.create_service( + ServiceRequestDetails, + "/rosapi/service_request_details", + self.get_service_request_details, + ) + self.create_service( + ServiceResponseDetails, + "/rosapi/service_response_details", + self.get_service_response_details, + ) + self.create_service(SetParam, "/rosapi/set_param", self.set_param) + self.create_service(GetParam, "/rosapi/get_param", self.get_param) + self.create_service(HasParam, "/rosapi/has_param", self.has_param) + self.create_service(DeleteParam, "/rosapi/delete_param", self.delete_param) + self.create_service(GetParamNames, "/rosapi/get_param_names", self.get_param_names) + self.create_service(GetTime, "/rosapi/get_time", self.get_time) + self.create_service(GetROSVersion, "/rosapi/get_ros_version", self.get_ros_version) + + def get_globs(self): + return glob_helper.get_globs(self) + + def get_topics(self, request, response): + """Called by the rosapi/Topics service. Returns a list of all the topics being published.""" + response.topics, response.types = proxy.get_topics_and_types(self.globs.topics) + return response + + def get_topics_for_type(self, request, response): + """Called by the rosapi/TopicsForType service. Returns a list of all the topics that are publishing a given type""" + response.topics = proxy.get_topics_for_type(request.type, self.globs.topics) + return response + + def get_topics_and_raw_types(self, request, response): + """Called by the rosapi/TopicsAndRawTypes service. Returns a list of all the topics being published, and their + raw types, similar to `gendeps --cat`.""" + response.topics, response.types = proxy.get_topics_and_types(self.globs.topics) + response.typedefs_full_text = [ + objectutils.get_typedef_full_text(type) for type in response.types + ] + return response + + def get_services(self, request, response): + """Called by the rosapi/Services service. Returns a list of all the services being advertised.""" + response.services = proxy.get_services(self.globs.services) + return response + + def get_services_for_type(self, request, response): + """Called by the rosapi/ServicesForType service. Returns a list of all the services that are publishing a given type""" + response.services = proxy.get_services_for_type(request.type, self.globs.services) + return response + + def get_nodes(self, request, response): + """Called by the rosapi/Nodes service. Returns a list of all the nodes that are registered""" + response.nodes = proxy.get_nodes() + return response + + def get_node_details(self, request, response): + """Called by the rosapi/Nodes service. Returns a node description""" + ( + response.subscribing, + response.publishing, + response.services, + ) = proxy.get_node_info(request.node) + return response + + def get_action_servers(self, request, response): + """Called by the rosapi/GetActionServers service. Returns a list of action servers based on actions standard topics""" + topics = proxy.get_topics(self.globs.topics, include_hidden=True) + response.action_servers = proxy.filter_action_servers(topics) + return response + + def get_topic_type(self, request, response): + """Called by the rosapi/TopicType service. Given the name of a topic, returns the name of the type of that topic. + Request class has one field, 'topic', which is a string value (the name of the topic) + Response class has one field, 'type', which is a string value (the type of the topic) + If the topic does not exist, an empty string is returned.""" + response.type = proxy.get_topic_type(request.topic, self.globs.topics) + return response + + def get_service_type(self, request, response): + """Called by the rosapi/ServiceType service. Given the name of a service, returns the type of that service + Request class has one field, 'service', which is a string value (the name of the service) + Response class has one field, 'type', which is a string value (the type of the service) + If the service does not exist, an empty string is returned.""" + response.type = proxy.get_service_type(request.service, self.globs.services) + return response + + def get_publishers(self, request, response): + """Called by the rosapi/Publishers service. Given the name of a topic, returns a list of node names + that are publishing on that topic.""" + response.publishers = proxy.get_publishers(request.topic, self.globs.topics) + return response + + def get_subscribers(self, request, response): + """Called by the rosapi/Subscribers service. Given the name of a topic, returns a list of node names + that are subscribing to that topic.""" + response.subscribers = proxy.get_subscribers(request.topic, self.globs.topics) + return response + + def get_service_providers(self, request, response): + """Called by the rosapi/ServiceProviders service. Given the name of a topic, returns a list of node names + that are advertising that service type""" + response.providers = proxy.get_service_providers(request.service, self.globs.services) + return response + + def get_service_node(self, request, response): + """Called by the rosapi/ServiceNode service. Given the name of a service, returns the name of the node + that is providing that service.""" + response.node = proxy.get_service_node(request.service, self.globs.services) + return response + + def get_message_details(self, request, response): + """Called by the rosapi/MessageDetails service. Given the name of a message type, returns the TypeDef + for that type.""" + response.typedefs = [ + dict_to_typedef(d) for d in objectutils.get_typedef_recursive(request.type) + ] + return response + + def get_service_request_details(self, request, response): + """Called by the rosapi/ServiceRequestDetails service. Given the name of a service type, returns the TypeDef + for the request message of that service type.""" + response.typedefs = [ + dict_to_typedef(d) + for d in objectutils.get_service_request_typedef_recursive(request.type) + ] + return response + + def get_service_response_details(self, request, response): + """Called by the rosapi/ServiceResponseDetails service. Given the name of a service type, returns the TypeDef + for the response message of that service type.""" + response.typedefs = [ + dict_to_typedef(d) + for d in objectutils.get_service_response_typedef_recursive(request.type) + ] + return response + + def set_param(self, request, response): + try: + node_name, param_name = self._get_node_and_param_name(request.name) + params.set_param(node_name, param_name, request.value, self.globs.params) + except ValueError: + self._print_malformed_param_name_warning(request.name) + return response + + def get_param(self, request, response): + try: + node_name, param_name = self._get_node_and_param_name(request.name) + response.value = params.get_param( + node_name, param_name, request.default_value, self.globs.params + ) + except ValueError: + self._print_malformed_param_name_warning(request.name) + return response + + def has_param(self, request, response): + try: + node_name, param_name = self._get_node_and_param_name(request.name) + response.exists = params.has_param(node_name, param_name, self.globs.params) + except ValueError: + self._print_malformed_param_name_warning(request.name) + return response + + def delete_param(self, request, response): + params.delete_param(request.node_name, request.name, self.globs.params) + return response + + def get_param_names(self, request, response): + response.names = params.get_param_names(self.globs.params) + return response + + def get_time(self, request, response): + response.time = Clock(clock_type=ClockType.ROS_TIME).now().to_msg() + return response + + def _get_node_and_param_name(self, param): + return tuple(param.split(":")) + + def _print_malformed_param_name_warning(self, param_name): + self.get_logger().warn( + "Malformed parameter name: {}; expecting :".format(param_name) + ) + + def get_ros_version(self, request, response): + response.version = 2 + response.distro = str(os.environ["ROS_DISTRO"]) + return response + + +def dict_to_typedef(typedefdict): + typedef = TypeDef() + typedef.type = typedefdict["type"] + typedef.fieldnames = typedefdict["fieldnames"] + typedef.fieldtypes = typedefdict["fieldtypes"] + typedef.fieldarraylen = typedefdict["fieldarraylen"] + typedef.examples = typedefdict["examples"] + typedef.constnames = typedefdict["constnames"] + typedef.constvalues = typedefdict["constvalues"] + return typedef + + +def main(args=None): + if args is None: + args = sys.argv + + rclpy.init(args=args) + node = Rosapi() + try: + rclpy.spin(node) + node.destroy_node() + rclpy.shutdown() + except KeyboardInterrupt: + print("Exiting due to SIGINT") + + +if __name__ == "__main__": + main() diff --git a/src/tools/opendrive_utils/COLCON_IGNORE b/src/interface/rosbridge_suite/rosapi/src/rosapi/__init__.py similarity index 100% rename from src/tools/opendrive_utils/COLCON_IGNORE rename to src/interface/rosbridge_suite/rosapi/src/rosapi/__init__.py diff --git a/src/interface/rosbridge_suite/rosapi/src/rosapi/glob_helper.py b/src/interface/rosbridge_suite/rosapi/src/rosapi/glob_helper.py new file mode 100644 index 000000000..e62883016 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/src/rosapi/glob_helper.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +import fnmatch +from collections import namedtuple + +from rcl_interfaces.msg import ParameterType + +Globs = namedtuple("Globs", ["topics", "services", "params"]) + + +def get_globs(node): + def get_param(parameter_name): + parameter_value = node.get_parameter(parameter_name).get_parameter_value() + if parameter_value.type == ParameterType.PARAMETER_STRING: + parameter_value = parameter_value.string_value + else: + parameter_value = "" + # strips array delimiters in case of an array style value + return [ + element.strip().strip("'") + for element in parameter_value.strip("[").strip("]").split(",") + if len(element.strip().strip("'")) > 0 + ] + + topics_glob = get_param("topics_glob") + services_glob = get_param("services_glob") + params_glob = get_param("params_glob") + return Globs(topics_glob, services_glob, params_glob) + + +def filter_globs(globs, full_list): + # If the globs are empty (weren't defined in the params), return the full list + if globs is not None and len(globs) > 0: + return list(filter(lambda x: any_match(x, globs), full_list)) + else: + return full_list + + +def any_match(query, globs): + return ( + globs is None or len(globs) == 0 or any(fnmatch.fnmatch(str(query), glob) for glob in globs) + ) diff --git a/src/interface/rosbridge_suite/rosapi/src/rosapi/objectutils.py b/src/interface/rosbridge_suite/rosapi/src/rosapi/objectutils.py new file mode 100644 index 000000000..49877d078 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/src/rosapi/objectutils.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import inspect + +from rosapi.stringify_field_types import stringify_field_types +from rosbridge_library.internal import ros_loader + +# Keep track of atomic types and special types +atomics = [ + "bool", + "byte", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + "string", +] +specials = ["time", "duration"] + + +def get_typedef(type): + """A typedef is a dict containing the following fields: + - string type + - string[] fieldnames + - string[] fieldtypes + - int[] fieldarraylen + - string[] examples + - string[] constnames + - string[] constvalues + get_typedef will return a typedef dict for the specified message type""" + if type in atomics: + # Atomics don't get a typedef + return None + + if type in specials: + # Specials get their type def mocked up + return _get_special_typedef(type) + + # Fetch an instance and return its typedef + instance = ros_loader.get_message_instance(type) + return _get_typedef(instance) + + +def get_service_request_typedef(servicetype): + """Returns a typedef dict for the service request class for the specified service type""" + # Get an instance of the service request class and return its typedef + instance = ros_loader.get_service_request_instance(servicetype) + return _get_typedef(instance) + + +def get_service_response_typedef(servicetype): + """Returns a typedef dict for the service response class for the specified service type""" + # Get an instance of the service response class and return its typedef + instance = ros_loader.get_service_response_instance(servicetype) + return _get_typedef(instance) + + +def get_typedef_recursive(type): + """Returns a list of typedef dicts for this type and all contained type fields""" + # Just go straight into the recursive method + return _get_typedefs_recursive(type, []) + + +def get_service_request_typedef_recursive(servicetype): + """Returns a list of typedef dicts for this type and all contained type fields""" + # Get an instance of the service request class and get its typedef + instance = ros_loader.get_service_request_instance(servicetype) + typedef = _get_typedef(instance) + + # Return the list of sub-typedefs + return _get_subtypedefs_recursive(typedef, []) + + +def get_service_response_typedef_recursive(servicetype): + """Returns a list of typedef dicts for this type and all contained type fields""" + # Get an instance of the service response class and get its typedef + instance = ros_loader.get_service_response_instance(servicetype) + typedef = _get_typedef(instance) + + # Return the list of sub-typedefs + return _get_subtypedefs_recursive(typedef, []) + + +def get_typedef_full_text(ty): + """Returns the full text (similar to `gendeps --cat`) for the specified message type""" + try: + return stringify_field_types(ty) + except Exception as e: + return f"# failed to get full definition text for {ty}: {str(e)}" + + +def _get_typedef(instance): + """Gets a typedef dict for the specified instance""" + if ( + instance is None + or not hasattr(instance, "__slots__") + or not hasattr(instance, "_fields_and_field_types") + ): + return None + + fieldnames = [] + fieldtypes = [] + fieldarraylen = [] + examples = [] + constnames = [] + constvalues = [] + for i in range(len(instance.__slots__)): + # Pull out the name + name = instance.__slots__[i] + fieldnames.append(name) + + # Pull out the type and determine whether it's an array + field_type = instance._fields_and_field_types[name[1:]] # Remove trailing underscore. + arraylen = -1 + if field_type[-1:] == "]": + if field_type[-2:-1] == "[": + arraylen = 0 + field_type = field_type[:-2] + else: + split = field_type.find("[") + arraylen = int(field_type[split + 1 : -1]) + field_type = field_type[:split] + fieldarraylen.append(arraylen) + + # Get the fully qualified type + field_instance = getattr(instance, name) + fieldtypes.append(_type_name(field_type, field_instance)) + + # Set the example as appropriate + example = field_instance + if arraylen >= 0: + example = [] + elif field_type not in atomics: + example = {} + examples.append(str(example)) + + # Add pseudo constants names and values filtering members + attributes = inspect.getmembers(instance) + for attribute in attributes: + if ( + attribute[0] not in instance.__slots__ + and not attribute[0].startswith("_") + and not inspect.isroutine(attribute[1]) + ): + constnames.append(str(attribute[0])) + constvalues.append(str(attribute[1])) + + typedef = { + "type": _type_name_from_instance(instance), + "fieldnames": fieldnames, + "fieldtypes": fieldtypes, + "fieldarraylen": fieldarraylen, + "examples": examples, + "constnames": constnames, + "constvalues": constvalues, + } + + return typedef + + +def _get_special_typedef(type): + example = None + if type == "time" or type == "duration": + example = { + "type": type, + "fieldnames": ["secs", "nsecs"], + "fieldtypes": ["int32", "int32"], + "fieldarraylen": [-1, -1], + "examples": ["0", "0"], + "constnames": [], + "constvalues": [], + } + return example + + +def _get_typedefs_recursive(type, typesseen): + """returns the type def for this type as well as the type defs for any fields within the type""" + if type in typesseen: + # Don't put a type if it's already been seen + return [] + + # Note that we have now seen this type + typesseen.append(type) + + # Get the typedef for this type and make sure it's not None + typedef = get_typedef(type) + + return _get_subtypedefs_recursive(typedef, typesseen) + + +def _get_subtypedefs_recursive(typedef, typesseen): + if typedef is None: + return [] + + # Create the list of subtypes and get the typedefs for fields + typedefs = [typedef] + for fieldtype in typedef["fieldtypes"]: + typedefs = typedefs + _get_typedefs_recursive(fieldtype, typesseen) + + return typedefs + + +def _type_name(type, instance): + """given a short type, and an object instance of that type, + determines and returns the fully qualified type""" + # The fully qualified type of atomic and special types is just their original name + if type in atomics or type in specials: + return type + + # If the instance is a list, then we can get no more information from the instance. + # However, luckily, the 'type' field for list types is usually already inflated to the full type. + if isinstance(instance, list): + return type + + # Otherwise, the type will come from the module and class name of the instance + return _type_name_from_instance(instance) + + +def _type_name_from_instance(instance): + mod = instance.__module__ + type = mod[0 : mod.find(".")] + "/" + instance.__class__.__name__ + return type diff --git a/src/interface/rosbridge_suite/rosapi/src/rosapi/params.py b/src/interface/rosbridge_suite/rosapi/src/rosapi/params.py new file mode 100644 index 000000000..2e88455ef --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/src/rosapi/params.py @@ -0,0 +1,243 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import fnmatch +import threading +from json import dumps, loads + +import rclpy +from rcl_interfaces.msg import Parameter, ParameterType, ParameterValue +from rcl_interfaces.srv import ListParameters +from ros2node.api import get_absolute_node_name +from ros2param.api import call_get_parameters, call_set_parameters, get_parameter_value +from rosapi.proxy import get_nodes + +""" Methods to interact with the param server. Values have to be passed +as JSON in order to facilitate dynamically typed SRV messages """ + +# Ensure thread safety for setting / getting parameters. +param_server_lock = threading.RLock() +_node = None +_parent_node_name = "" + +_parameter_type_mapping = [ + "", + "bool_value", + "integer_value", + "double_value", + "string_value", + "byte_array_value", + "bool_array_value", + "integer_array_value", + "double_array_value", + "string_array_value", +] + + +def init(parent_node_name): + """ + Initializes params module with a rclpy.node.Node for further use. + This function has to be called before any other for the module to work. + """ + global _node, _parent_node_name + # TODO(@jubeira): remove this node; use rosapi node with MultiThreadedExecutor or + # async / await to prevent the service calls from blocking. + parent_node_basename = parent_node_name.split("/")[-1] + param_node_name = f"{parent_node_basename}_params" + _node = rclpy.create_node( + param_node_name, cli_args=["--ros-args", "-r", f"__node:={param_node_name}"] + ) + _parent_node_name = get_absolute_node_name(parent_node_name) + + +def set_param(node_name, name, value, params_glob): + """Sets a parameter in a given node""" + + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + # If the glob list is not empty and there are no glob matches, + # stop the attempt to set the parameter. + return + # If the glob list is empty (i.e. false) or the parameter matches + # one of the glob strings, continue to set the parameter. + d = None + try: + d = loads(value) + value = d if isinstance(d, str) else value + except ValueError: + raise Exception( + "Due to the type flexibility of the ROS parameter server, the value argument to set_param must be a JSON-formatted string." + ) + + node_name = get_absolute_node_name(node_name) + with param_server_lock: + _set_param(node_name, name, value) + + +def _set_param(node_name, name, value, parameter_type=None): + """ + Internal helper function for set_param. + Attempts to set the given parameter in the target node with the desired value, + deducing the parameter type if it's not specified. + parameter_type allows forcing a type for the given value; this is useful to delete parameters. + """ + parameter = Parameter() + parameter.name = name + if parameter_type is None: + parameter.value = get_parameter_value(string_value=value) + else: + parameter.value = ParameterValue() + parameter.value.type = parameter_type + if parameter_type != ParameterType.PARAMETER_NOT_SET: + setattr(parameter.value, _parameter_type_mapping[parameter_type]) + + try: + # call_get_parameters will fail if node does not exist. + call_set_parameters(node=_node, node_name=node_name, parameters=[parameter]) + except Exception: + pass + + +def get_param(node_name, name, default, params_glob): + """Gets a parameter from a given node""" + + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + # If the glob list is not empty and there are no glob matches, + # stop the attempt to get the parameter. + return + # If the glob list is empty (i.e. false) or the parameter matches + # one of the glob strings, continue to get the parameter. + if default != "": + try: + default = loads(default) + except ValueError: + pass # Keep default without modifications. + + node_name = get_absolute_node_name(node_name) + with param_server_lock: + try: + # call_get_parameters will fail if node does not exist. + response = call_get_parameters(node=_node, node_name=node_name, parameter_names=[name]) + pvalue = response.values[0] + # if type is 0 (parameter not set), the next line will raise an exception + # and return value shall go to default. + value = getattr(pvalue, _parameter_type_mapping[pvalue.type]) + except Exception: + # If either the node or the parameter does not exist, return default. + value = default + + return dumps(value) + + +def has_param(node_name, name, params_glob): + """Checks whether a given node has a parameter or not""" + + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + # If the glob list is not empty and there are no glob matches, + # stop the attempt to set the parameter. + return False + # If the glob list is empty (i.e. false) or the parameter matches + # one of the glob strings, check whether the parameter exists. + node_name = get_absolute_node_name(node_name) + with param_server_lock: + try: + response = call_get_parameters(node=_node, node_name=node_name, parameter_names=[name]) + except Exception: + return False + + return response.values[0].type > 0 and response.values[0].type < len(_parameter_type_mapping) + + +def delete_param(node_name, name, params_glob): + """Deletes a parameter in a given node""" + + if params_glob and not any(fnmatch.fnmatch(str(name), glob) for glob in params_glob): + # If the glob list is not empty and there are no glob matches, + # stop the attempt to delete the parameter. + return + # If the glob list is empty (i.e. false) or the parameter matches + # one of the glob strings, continue to delete the parameter. + node_name = get_absolute_node_name(node_name) + if has_param(node_name, name, params_glob): + with param_server_lock: + _set_param(node_name, name, None, ParameterType.PARAMETER_NOT_SET) + + +def get_param_names(params_glob): + params = [] + nodes = get_nodes() + + for node in nodes: + params.extend(get_node_param_names(node, params_glob)) + + return params + + +def get_node_param_names(node_name, params_glob): + """Gets list of parameter names for a given node""" + node_name = get_absolute_node_name(node_name) + + with param_server_lock: + if params_glob: + # If there is a parameter glob, filter by it. + return list( + filter( + lambda x: any(fnmatch.fnmatch(str(x), glob) for glob in params_glob), + _get_param_names(node_name), + ) + ) + else: + # If there is no parameter glob, don't filter. + return _get_param_names(node_name) + + +def _get_param_names(node_name): + # This method is called in a service callback; calling a service of the same node + # will cause a deadlock. + global _parent_node_name + if node_name == _parent_node_name: + return [] + + client = _node.create_client(ListParameters, f"{node_name}/list_parameters") + + ready = client.wait_for_service(timeout_sec=5.0) + if not ready: + raise RuntimeError("Wait for list_parameters service timed out") + + request = ListParameters.Request() + future = client.call_async(request) + rclpy.spin_until_future_complete(_node, future) + response = future.result() + + if response is not None: + return [f"{node_name}:{param_name}" for param_name in response.result.names] + else: + return [] diff --git a/src/interface/rosbridge_suite/rosapi/src/rosapi/proxy.py b/src/interface/rosbridge_suite/rosapi/src/rosapi/proxy.py new file mode 100644 index 000000000..c3bdbb4a0 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/src/rosapi/proxy.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from ros2node.api import ( + get_node_names, + get_publisher_info, + get_service_server_info, + get_subscriber_info, +) +from ros2service.api import get_service_names, get_service_names_and_types +from ros2topic.api import get_topic_names, get_topic_names_and_types + +from .glob_helper import any_match, filter_globs + +_node = None + + +def init(node): + """ + Initializes proxy module with a rclpy.node.Node for further use. + This function has to be called before any other for the module to work. + """ + global _node + _node = node + + +def get_topics(topics_glob, include_hidden=False): + """Returns a list of all the active topics in the ROS system""" + topic_names = get_topic_names(node=_node, include_hidden_topics=include_hidden) + return filter_globs(topics_glob, topic_names) + + +def get_topics_and_types(topics_glob, include_hidden=False): + return get_publications_and_types( + topics_glob, get_topic_names_and_types, include_hidden_topics=include_hidden + ) + + +def get_topics_for_type(topic_type, topics_glob, include_hidden=False): + topic_names_and_types = get_topic_names_and_types( + node=_node, include_hidden_topics=include_hidden + ) + # topic[0] has the topic name and topic[1] has the type wrapped in a list. + topics_for_type = [topic[0] for topic in topic_names_and_types if topic[1][0] == topic_type] + return filter_globs(topics_glob, topics_for_type) + + +def get_services(services_glob, include_hidden=False): + """Returns a list of all the services advertised in the ROS system""" + # Filter the list of services by whether they are public before returning. + service_names = get_service_names(node=_node, include_hidden_services=include_hidden) + return filter_globs(services_glob, service_names) + + +def get_services_and_types(services_glob, include_hidden=False): + return get_publications_and_types( + services_glob, + get_service_names_and_types, + include_hidden_services=include_hidden, + ) + + +def get_services_for_type(service_type, services_glob, include_hidden=False): + """Returns a list of services as specific service type""" + # Filter the list of services by whether they are public before returning. + services_names_and_types = get_service_names_and_types( + node=_node, include_hidden_services=include_hidden + ) + # service[0] has the topic name and service[1] has the type wrapped in a list. + services_for_type = [ + service[0] for service in services_names_and_types if service[1][0] == service_type + ] + return filter_globs(services_glob, services_for_type) + + +def get_publications_and_types(glob, getter_function, **include_hidden_publications): + """Generic getter function for both services and topics""" + publication_names_and_types = getter_function(node=_node, **include_hidden_publications) + # publication[0] has the publication name and publication[1] has the type wrapped in a list. + all_publications = [publication[0] for publication in publication_names_and_types] + filtered_publications = filter_globs(glob, all_publications) + filtered_publication_types = [ + publication[1][0] + for publication in publication_names_and_types + if publication[0] in filtered_publications + ] + return filtered_publications, filtered_publication_types + + +def get_nodes(include_hidden=False): + """Returns a list of all the nodes registered in the ROS system""" + node_names = get_node_names(node=_node, include_hidden_nodes=include_hidden) + full_names = [node_name.full_name for node_name in node_names] + return full_names + + +def get_node_info(node_name, include_hidden=False): + node_names = get_node_names(node=_node, include_hidden_nodes=include_hidden) + if node_name in [n.full_name for n in node_names]: + # Only the name of each item is required as output. + subscribers = get_node_subscriptions(node_name) + publishers = get_node_publications(node_name) + services = get_node_services(node_name) + + return subscribers, publishers, services + + +def get_node_publications(node_name): + """Returns a list of topic names that are being published by the specified node""" + publishers = get_publisher_info(node=_node, remote_node_name=node_name) + return [publisher.name for publisher in publishers] + + +def get_node_subscriptions(node_name): + """Returns a list of topic names that are being subscribed by the specified node""" + subscribers = get_subscriber_info(node=_node, remote_node_name=node_name) + return [subscriber.name for subscriber in subscribers] + + +def get_node_services(node_name): + """Returns a list of service names that are being hosted by the specified node""" + services = get_service_server_info(node=_node, remote_node_name=node_name) + return [service.name for service in services] + + +def get_node_service_types(node_name): + """Returns a list of service types that are being hosted by the specified node""" + services = get_service_server_info(node=_node, remote_node_name=node_name) + return [service.types[0] for service in services] + + +def get_topic_type(topic, topics_glob): + """Returns the type of the specified ROS topic""" + # Note: this doesn't consider hidden topics. + topics, types = get_topics_and_types(topics_glob) + try: + return types[topics.index(topic)] + except ValueError: + # Return empty string if the topic is not present. + return "" + + +def filter_action_servers(topics): + """Returns a list of action servers""" + # Note(@jubeira): filtering by topic should be enough; services can be taken into account as well. + action_servers = [] + possible_action_server = "" + possibility = [0, 0] + + action_topics = ["feedback", "status"] + for topic in sorted(topics): + split = topic.split("/") + if len(split) >= 4: + topic = split.pop() + action_prefix = split.pop() + if action_prefix != "_action": + continue + + namespace = "/".join(split) + if possible_action_server != namespace: + possible_action_server = namespace + possibility = [0, 0] + if possible_action_server == namespace and topic in action_topics: + possibility[action_topics.index(topic)] = 1 + if all(p == 1 for p in possibility): + action_servers.append(possible_action_server) + possibility = [0, 0] + + return action_servers + + +def get_service_type(service, services_glob): + """Returns the type of the specified ROS service,""" + # Note: this doesn't consider hidden services. + services, types = get_services_and_types(services_glob) + try: + return types[services.index(service)] + except ValueError: + # Return empty string if the service is not present. + return "" + + +def get_channel_info(channel, channels_glob, getter_function, include_hidden=False): + """Returns a list of node names that are publishing / subscribing to the specified topic, + or advertising a given service.""" + if any_match(str(channel), channels_glob): + channel_info_list = [] + node_list = get_nodes(include_hidden) + for node in node_list: + channel_info = getter_function(node) + if channel in channel_info: + channel_info_list.append(node) + return channel_info_list + else: + return [] + + +def get_publishers(topic, topics_glob, include_hidden=False): + """Returns a list of node names that are publishing the specified topic""" + return get_channel_info( + topic, topics_glob, get_node_publications, include_hidden=include_hidden + ) + + +def get_subscribers(topic, topics_glob, include_hidden=False): + """Returns a list of node names that are subscribing to the specified topic""" + return get_channel_info( + topic, topics_glob, get_node_subscriptions, include_hidden=include_hidden + ) + + +def get_service_providers(queried_type, services_glob, include_hidden=False): + """Returns a list of node names that are advertising a service with the specified type""" + return get_channel_info( + queried_type, + services_glob, + get_node_service_types, + include_hidden=include_hidden, + ) + + +def get_service_node(queried_type, services_glob, include_hidden=False): + """Returns the name of the node that is providing the given service, or empty string""" + node_name = get_channel_info( + queried_type, services_glob, get_node_services, include_hidden=include_hidden + ) + if node_name: + return node_name[0] + else: + return "" diff --git a/src/interface/rosbridge_suite/rosapi/src/rosapi/stringify_field_types.py b/src/interface/rosbridge_suite/rosapi/src/rosapi/stringify_field_types.py new file mode 100644 index 000000000..10d4288ec --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/src/rosapi/stringify_field_types.py @@ -0,0 +1,33 @@ +from rosidl_adapter.parser import parse_message_string +from rosidl_runtime_py import get_interface_path + + +def stringify_field_types(root_type): + definition = "" + seen_types = set() + deps = [root_type] + is_root = True + while deps: + ty = deps.pop() + parts = ty.split("/") + if not is_root: + definition += "\n================================================================================\n" + definition += f"MSG: {ty}\n" + is_root = False + + msg_name = parts[2] if len(parts) == 3 else parts[1] + interface_name = ty if len(parts) == 3 else f"{parts[0]}/msg/{parts[1]}" + with open(get_interface_path(interface_name), encoding="utf-8") as msg_file: + msg_definition = msg_file.read() + definition += msg_definition + + spec = parse_message_string(parts[0], msg_name, msg_definition) + for field in spec.fields: + is_builtin = field.type.pkg_name is None + if not is_builtin: + field_ty = f"{field.type.pkg_name}/{field.type.type}" + if field_ty not in seen_types: + deps.append(field_ty) + seen_types.add(field_ty) + + return definition diff --git a/src/interface/rosbridge_suite/rosapi/test/__init__.py b/src/interface/rosbridge_suite/rosapi/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosapi/test/test_stringify_field_types.py b/src/interface/rosbridge_suite/rosapi/test/test_stringify_field_types.py new file mode 100644 index 000000000..a1d43563e --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi/test/test_stringify_field_types.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +import unittest + +from rosapi.stringify_field_types import stringify_field_types +from rosbridge_library.internal.ros_loader import InvalidModuleException + + +class TestObjectUtils(unittest.TestCase): + def test_stringify_field_types(self): + self.maxDiff = None + + self.assertRegex( + stringify_field_types("std_msgs/String"), + r"(?ms)^string data", + ) + + self.assertRegex( + stringify_field_types("std_msgs/msg/String"), + r"(?ms)^string data", + ) + + self.assertRegex( + stringify_field_types("std_msgs/ByteMultiArray"), + r"""(?s) +MultiArrayLayout layout.* +byte\[\] data.* + +================================================================================ +MSG: std_msgs/MultiArrayLayout +.* +MultiArrayDimension\[\] dim.* +uint32 data_offset.* + +================================================================================ +MSG: std_msgs/MultiArrayDimension +.* +string label.* +uint32 size.* +uint32 stride.* +""", + ) + self.assertRegex( + stringify_field_types("sensor_msgs/Image"), + r"""(?s) +std_msgs/Header header.* +.* +uint32 height.* +uint32 width.* +.* +string encoding.* +.* +uint8 is_bigendian.* +uint32 step.* +uint8\[\] data.* + +================================================================================ +MSG: std_msgs/Header +.* +builtin_interfaces/Time stamp.* +string frame_id + +================================================================================ +MSG: builtin_interfaces/Time +.* +int32 sec.* +uint32 nanosec +""", + ) + self.assertRegex( + stringify_field_types("sensor_msgs/CameraInfo"), + r"""(?s) +std_msgs/Header header.* +uint32 height.* +uint32 width.* +string distortion_model.* +float64\[\] d.* +float64\[9\] k.* +float64\[9\] r.* +float64\[12\] p.* +uint32 binning_x.* +uint32 binning_y.* +RegionOfInterest roi.* + +================================================================================ +MSG: sensor_msgs/RegionOfInterest +.* +uint32 x_offset.* +uint32 y_offset.* +uint32 height.* +uint32 width.* +bool do_rectify + +================================================================================ +MSG: std_msgs/Header +.* +builtin_interfaces/Time stamp.* +string frame_id + +================================================================================ +MSG: builtin_interfaces/Time +.* +int32 sec.* +uint32 nanosec +""", + ) + + self.assertRegex( + stringify_field_types("shape_msgs/SolidPrimitive"), + r"""(?s) +uint8 BOX=1.* +uint8 SPHERE=2.* +uint8 CYLINDER=3.* +uint8 CONE=4.* +uint8 type.* +float64\[<=3\] dimensions.* +uint8 BOX_X=0.* +uint8 BOX_Y=1.* +uint8 BOX_Z=2.* +uint8 SPHERE_RADIUS=0.* +uint8 CYLINDER_HEIGHT=0.* +uint8 CYLINDER_RADIUS=1.* +uint8 CONE_HEIGHT=0.* +uint8 CONE_RADIUS=1.* +""", + ) + + self.assertEqual( + stringify_field_types("geometry_msgs/Quaternion"), + """\ +# This represents an orientation in free space in quaternion form. + +float64 x 0 +float64 y 0 +float64 z 0 +float64 w 1 +""", + ) + + try: + self.assertEqual( + stringify_field_types("rmw_dds_common/NodeEntitiesInfo"), + """\ +string<=256 node_namespace +string<=256 node_name +Gid[] reader_gid_seq +Gid[] writer_gid_seq + +================================================================================ +MSG: rmw_dds_common/Gid +char[24] data +""", + ) + except InvalidModuleException: + # This message is not present on older ROS distributions + pass diff --git a/src/interface/rosbridge_suite/rosapi_msgs/CHANGELOG.rst b/src/interface/rosbridge_suite/rosapi_msgs/CHANGELOG.rst new file mode 100644 index 000000000..fd75ceb30 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/CHANGELOG.rst @@ -0,0 +1,25 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosapi_msgs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.3.1 (2022-10-21) +------------------ + +1.3.0 (2022-08-16) +------------------ + +1.2.0 (2022-05-20) +------------------ +* Added `/rosapi/get_ros_version` service (`#708 `_) +* Contributors: Jacob Bandes-Storch, Kedus Mathewos + +1.1.2 (2022-01-03) +------------------ + +1.1.1 (2021-12-09) +------------------ + +1.1.0 (2021-10-22) +------------------ +* Move msg/srv from rosapi and rosbridge_library into separate packages; enable Rolling in CI (`#665 `_) +* Contributors: Jacob Bandes-Storch diff --git a/src/interface/rosbridge_suite/rosapi_msgs/CMakeLists.txt b/src/interface/rosbridge_suite/rosapi_msgs/CMakeLists.txt new file mode 100644 index 000000000..477ab48e4 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.5) +project(rosapi_msgs) + +find_package(ament_cmake_ros REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + msg/TypeDef.msg + srv/DeleteParam.srv + srv/GetActionServers.srv + srv/GetParam.srv + srv/GetParamNames.srv + srv/GetROSVersion.srv + srv/GetTime.srv + srv/HasParam.srv + srv/MessageDetails.srv + srv/Nodes.srv + srv/NodeDetails.srv + srv/Publishers.srv + srv/ServiceNode.srv + srv/ServiceProviders.srv + srv/ServiceRequestDetails.srv + srv/ServiceResponseDetails.srv + srv/Services.srv + srv/ServicesForType.srv + srv/ServiceType.srv + srv/SetParam.srv + srv/Subscribers.srv + srv/Topics.srv + srv/TopicsAndRawTypes.srv + srv/TopicsForType.srv + srv/TopicType.srv + DEPENDENCIES builtin_interfaces +) + +ament_export_dependencies(builtin_interfaces rosidl_default_runtime) + +ament_package() diff --git a/src/interface/rosbridge_suite/rosapi_msgs/msg/TypeDef.msg b/src/interface/rosbridge_suite/rosapi_msgs/msg/TypeDef.msg new file mode 100644 index 000000000..48a6f35da --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/msg/TypeDef.msg @@ -0,0 +1,7 @@ +string type +string[] fieldnames +string[] fieldtypes +int32[] fieldarraylen +string[] examples +string[] constnames +string[] constvalues diff --git a/src/interface/rosbridge_suite/rosapi_msgs/package.xml b/src/interface/rosbridge_suite/rosapi_msgs/package.xml new file mode 100644 index 000000000..bc2920e96 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/package.xml @@ -0,0 +1,35 @@ + + + rosapi_msgs + 1.3.1 + + Provides service calls for getting ros meta-information, like list of + topics, services, params, etc. + + + BSD + + http://ros.org/wiki/rosapi + https://github.com/RobotWebTools/rosbridge_suite/issues + https://github.com/RobotWebTools/rosbridge_suite + + Jonathan Mace + Jihoon Lee + Foxglove + + ament_cmake_ros + + rosidl_default_generators + + builtin_interfaces + + builtin_interfaces + rcl_interfaces + rosidl_default_runtime + + rosidl_interface_packages + + + ament_cmake + + diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/DeleteParam.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/DeleteParam.srv new file mode 100644 index 000000000..22a97d597 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/DeleteParam.srv @@ -0,0 +1,2 @@ +string name +--- diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/GetActionServers.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetActionServers.srv new file mode 100644 index 000000000..5a835e04b --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetActionServers.srv @@ -0,0 +1,3 @@ + +--- +string[] action_servers diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/GetParam.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetParam.srv new file mode 100644 index 000000000..cdbf3fd17 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetParam.srv @@ -0,0 +1,4 @@ +string name +string default_value +--- +string value diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/GetParamNames.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetParamNames.srv new file mode 100644 index 000000000..536ee0c90 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetParamNames.srv @@ -0,0 +1,2 @@ +--- +string[] names diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/GetROSVersion.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetROSVersion.srv new file mode 100644 index 000000000..287420966 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetROSVersion.srv @@ -0,0 +1,3 @@ +--- +uint8 version +string distro diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/GetTime.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetTime.srv new file mode 100644 index 000000000..285ad7443 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/GetTime.srv @@ -0,0 +1,2 @@ +--- +builtin_interfaces/Time time diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/HasParam.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/HasParam.srv new file mode 100644 index 000000000..210c81eab --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/HasParam.srv @@ -0,0 +1,3 @@ +string name +--- +bool exists diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/MessageDetails.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/MessageDetails.srv new file mode 100644 index 000000000..722449676 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/MessageDetails.srv @@ -0,0 +1,3 @@ +string type +--- +TypeDef[] typedefs diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/NodeDetails.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/NodeDetails.srv new file mode 100644 index 000000000..7de5d39a4 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/NodeDetails.srv @@ -0,0 +1,5 @@ +string node +--- +string[] subscribing +string[] publishing +string[] services diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/Nodes.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/Nodes.srv new file mode 100644 index 000000000..3be5a63d1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/Nodes.srv @@ -0,0 +1,3 @@ + +--- +string[] nodes diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/Publishers.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/Publishers.srv new file mode 100644 index 000000000..baaa8e434 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/Publishers.srv @@ -0,0 +1,3 @@ +string topic +--- +string[] publishers diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceNode.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceNode.srv new file mode 100644 index 000000000..ac516bd22 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceNode.srv @@ -0,0 +1,3 @@ +string service +--- +string node diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceProviders.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceProviders.srv new file mode 100644 index 000000000..789dc0d4c --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceProviders.srv @@ -0,0 +1,3 @@ +string service +--- +string[] providers diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceRequestDetails.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceRequestDetails.srv new file mode 100644 index 000000000..722449676 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceRequestDetails.srv @@ -0,0 +1,3 @@ +string type +--- +TypeDef[] typedefs diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceResponseDetails.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceResponseDetails.srv new file mode 100644 index 000000000..722449676 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceResponseDetails.srv @@ -0,0 +1,3 @@ +string type +--- +TypeDef[] typedefs diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceType.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceType.srv new file mode 100644 index 000000000..4c7e2ecaf --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServiceType.srv @@ -0,0 +1,3 @@ +string service +--- +string type diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/Services.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/Services.srv new file mode 100644 index 000000000..5c44b4719 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/Services.srv @@ -0,0 +1,3 @@ + +--- +string[] services diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/ServicesForType.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServicesForType.srv new file mode 100644 index 000000000..74085b0d3 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/ServicesForType.srv @@ -0,0 +1,3 @@ +string type +--- +string[] services diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/SetParam.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/SetParam.srv new file mode 100644 index 000000000..426e15cec --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/SetParam.srv @@ -0,0 +1,3 @@ +string name +string value +--- diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/Subscribers.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/Subscribers.srv new file mode 100644 index 000000000..cd893b4c9 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/Subscribers.srv @@ -0,0 +1,3 @@ +string topic +--- +string[] subscribers diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicType.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicType.srv new file mode 100644 index 000000000..e08657a28 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicType.srv @@ -0,0 +1,3 @@ +string topic +--- +string type diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/Topics.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/Topics.srv new file mode 100644 index 000000000..32765ea15 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/Topics.srv @@ -0,0 +1,4 @@ + +--- +string[] topics +string[] types diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicsAndRawTypes.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicsAndRawTypes.srv new file mode 100644 index 000000000..12fb143a2 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicsAndRawTypes.srv @@ -0,0 +1,5 @@ + +--- +string[] topics +string[] types +string[] typedefs_full_text diff --git a/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicsForType.srv b/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicsForType.srv new file mode 100644 index 000000000..4afeaed32 --- /dev/null +++ b/src/interface/rosbridge_suite/rosapi_msgs/srv/TopicsForType.srv @@ -0,0 +1,3 @@ +string type +--- +string[] topics diff --git a/src/interface/rosbridge_suite/rosbridge_library/CHANGELOG.rst b/src/interface/rosbridge_suite/rosbridge_library/CHANGELOG.rst new file mode 100644 index 000000000..0761255d3 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/CHANGELOG.rst @@ -0,0 +1,617 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosbridge_library +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.3.1 (2022-10-21) +------------------ +* Optimized large binary array publishing (`#819 `_) +* Skip unnecessary conversion for cbor/cbor-raw compression (`#792 `_) (`#800 `_) +* Improve robustness for multiple client connections (`#803 `_) +* Minor performance improvements (`#809 `_) +* Remove unnecessary checking of topic globs. (`#793 `_) (`#799 `_) +* Fix duplicate subscription created with wrong 'raw' attribute. (`#798 `_) +* Contributors: Hans-Joachim Krauch, Steffen Nattke, Ted Sender + +1.3.0 (2022-08-16) +------------------ +* Allow integers in conversion to float array messages (`#777 `_) +* Non standard msg modules (`#735 `_) +* Contributors: Jacob Bandes-Storch, Will + +1.2.0 (2022-05-20) +------------------ +* Fixed float arrays conversion (`#730 `_) +* Fixed multiple subscriber on transient_local topic (`#723 `_) +* Fix translation of time and time arrays (`#691 `_) +* Fix array behavior (`#692 `_) +* Contributors: Jacob Bandes-Storch, José Castelo, Kenji Miyake, Will, p0rys + +1.1.2 (2022-01-03) +------------------ +* [694] update DurabilityPolicy api that are being deprecated (`#695 `_) +* Fix byte behavior (`#693 `_) +* Fix test_message_conversion.py (`#645 `_) +* Fix test_ros_loader.py (`#644 `_) +* Fix CI test configuration and temporarily disable rosbridge_library test (`#686 `_) +* Contributors: Evan Flynn, Jacob Bandes-Storch, Kenji Miyake + +1.1.1 (2021-12-09) +------------------ +* Allow subscribing to any qos profile when creating a subscriber (`#690 `_) +* Fix and add test for multiple subscribers to same topic (`#687 `_) +* Fix error when advertising duplicate service (`#683 `_) +* Fix incoming service calls (`#669 `_) +* Replace busy wait in AdvertiseService with async handler (`#666 `_) +* Contributors: Domenic Rodriguez, Jacob Bandes-Storch, Roman Shtylman + +1.1.0 (2021-10-22) +------------------ +* Fix test imports from rosbridge_test_msgs (`#668 `_) +* Move msg/srv from rosapi and rosbridge_library into separate packages; enable Rolling in CI (`#665 `_) +* Fix test_services.py (`#653 `_) +* Fix unused variables: flake8 --select=F841 (`#623 `_) +* Remove get_service_instance from ros_loader (`#647 `_) +* Fix test settings for rosbridge_library (`#643 `_) +* Fix DOS line endings (`#658 `_) +* Port `#464 `_, `#478 `_, `#496 `_, and `#502 `_ from ROS1 branch (`#663 `_) +* Add pre-commit, format with black and isort (`#648 `_) +* Contributors: Adrian Macneil, Christian Clauss, Domenic Rodriguez, Jacob Bandes-Storch, Kenji Miyake + +1.0.8 (2021-08-26) +------------------ +* Fix various Python code style and lint issues +* Contributors: Christian Clauss, Jacob Bandes-Storch + +1.0.7 (2021-08-18) +------------------ +* Fix typos discovered by codespell (`#600 `_) +* Contributors: Christian Clauss + +1.0.6 (2021-08-17) +------------------ +* Fix broken links in changelogs +* Contributors: Jacob Bandes-Storch + +1.0.5 (2021-08-12) +------------------ + +1.0.4 (2021-08-11) +------------------ + +1.0.3 (2021-08-03) +------------------ +* Add cbor-raw compression support (`#574 `_, adapted from ROS 1 implementation `#452 `_) +* Adaptations to Eloquent [Again] (`#533 `_) + * increase spin period to 1000Hz to allow 1000 messages per second into the websocket + * allow interpreting int as float when needed + * better handling array.array and numpy arrays + * allow bytes and str websocket messages + * add boolean type + * handle type extraction of static array rostypes + * missing cls variable + Co-authored-by: Maximilian Matthe + Co-authored-by: CoRoLa generic + Co-authored-by: joshwapohlmann +* Fix for type error caused by appending byte arrays to empty string buffer (`#507 `_) +* Contributors: Connor Brooks, Jacob Bandes-Storch, travipross + +1.0.2 (2019-09-24) +------------------ +* use Python 3 dependency keys (`#436 `_) + +1.0.1 (2019-09-20) +------------------ + +1.0.0 (2019-09-19) +------------------ +* Port to ROS 2 + +0.11.3 (2019-08-07) +------------------- + +0.11.2 (2019-07-08) +------------------- + +0.11.1 (2019-05-08) +------------------- +* fixed logwarn msg formatting in publishers (`#398 `_) +* Contributors: Gautham P Das + +0.11.0 (2019-03-29) +------------------- +* BSON can send Nan and Inf (`#391 `_) +* Contributors: akira_you + +0.10.2 (2019-03-04) +------------------- +* Fix typo (`#379 `_) +* Contributors: David Weis + +0.10.1 (2018-12-16) +------------------- +* Inline cbor library (`#377 `_) + Prefer system version with C speedups, but include pure Python implementation. +* Contributors: Matt Vollrath + +0.10.0 (2018-12-14) +------------------- +* CBOR encoding (`#364 `_) + * Add CBOR encoding + * Fix value extraction performance regression + Extract message values once per message. + * Fix typed array tags + Was using big-endian tags and encoding little-endian. + Always use little-endian for now since Intel is prevalent for desktop. + Add some comments to this effect. + * Update CBOR protocol documentation + More information about draft typed arrays and when to use CBOR. + * Fix 64-bit integer CBOR packing + Use an actual 64-bit format. +* use package format 2, remove unnecessary dependencies (`#348 `_) +* removing has_key for python3, keeping backwards compatibility (`#337 `_) + * removing has_key for python3, keeping backwards compatibility + * py3 change for itervalues, keeping py2 compatibility +* Contributors: Andreas Klintberg, Dirk Thomas, Matt Vollrath + +0.9.0 (2018-04-09) +------------------ +* Fix typo in function call +* Add missing argument to InvalidMessageException (`#323 `_) + Add missing argument to InvalidMessageException constructor +* Make unregister_timeout configurable (`#322 `_) + Pull request `#247 `_ introduces a 10 second delay to mitigate issue `#138 `_. + This change makes this delay configurable by passing an argument either + on the command line or when including a launch file. + Usage example: + ```xml + + + + + + ``` + Closes `#320 `_ +* message_conversion: create stand-alone object inst (`#319 `_) + Catching the ROSInitException allows to create object + instances without an initialized ROS state +* Fixes `#313 `_ by fixing has_binary in protocol.py (`#315 `_) + * Fixes `#313 `_ by fixing has_binary in protocol.py + Checks for lists that have binary content as well as dicts + * Minor refactoring for protocol.py +* fix fragment bug (`#316 `_) + * fix bug that lost data while sending large packets + * fixed travis ci failed by @T045T + * fixed travis ci failed by @T045T + * travis ci failed + * fix rosbridge_library/test/experimental/fragmentation+srv+tcp test bug + * sync .travis.yaml + * fix the service_response message bug + * fix the fragment paring error + * fix indentation of "service" line +* add graceful_shutdown() method to advertise_service capability + This gives the service a bit of time to cancel any in-flight service requests (which should fix `#265 `_). + This is important because we busy-wait for a rosbridge response for service calls and those threads do not get stopped otherwise. + Also, rospy service clients do not currently support timeouts, so any clients would be stuck too. + A new test case in test_service_capabilities.py verifies the fix works +* Add rostest for service capabilities and fix bugs + also fixed some typos +* Fix Travis config (`#311 `_) + * fix Travis config + dist: kinetic is currently unsupported + * fix rostests + for some reason, rostest seems to hide the rosout node - changed tests to use other services +* Contributors: Anwar, Johannes Rothe, Jørgen Borgesen, Nils Berg, Phil, WH-0501, elgarlepp + +0.8.6 (2017-12-08) +------------------ +* Import StringIO from StringIO if python2 and from io if python3 fixes `#306 `_ (`#307 `_) +* Contributors: Jihoon Lee + +0.8.5 (2017-11-23) +------------------ +* Raise if inappropriate bson module is installed (Appease `#198 `_) (`#270 `_) + * Raise Exception if inappropriate bson module is installed (Related to `#198 `_) +* Add Python3 compatibility (`#300 `_) + * First pass at Python 3 compatibility + * message_conversion: Only call encode on a Python2 str or bytes type + * protocol.py: Changes for dict in Python3. Compatible with Python 2 too. + * More Python 3 fixes, all tests pass + * Move definition of string_types to rosbridge_library.util +* Contributors: Junya Hayashi, Kartik Mohta + +0.8.4 (2017-10-16) +------------------ + +0.8.3 (2017-09-11) +------------------ +* Type conversion convention correction, correcting issue `#240 `_ +* Contributors: Alexis Paques + +0.8.2 (2017-09-11) +------------------ + +0.8.1 (2017-08-30) +------------------ +* remove ujson from dependency to build in trusty (`#290 `_) +* Contributors: Jihoon Lee + +0.8.0 (2017-08-30) +------------------ +* Cleaning up travis configuration (`#283 `_) + configure travis to use industial ci configuration. Now it uses xenial and kinetic +* Merge pull request `#272 `_ from ablakey/patch-1 + Prevent a KeyError when bson_only_mode is unset. +* Update protocol.py + Prevent a KeyError when bson_only_mode is unset. +* Merge pull request `#257 `_ from Sanic/bson-only-mode + Implemented a bson_only_mode flag for the TCP version of rosbridge +* Merge pull request `#247 `_ from v-lopez/develop + Delay unregister to mitigate `#138 `_ +* Change class constant to module constant +* Reduce timeout for tests + Tests will sleep for 10% extra of the timeout to prevent some situations + were the test sleep ended right before the unregister timer fired +* Fix test advertise errors after delayed unregister changes +* Fix missing tests due to delayed unregistration +* Move UNREGISTER_TIMEOUT to member class so it's accessible from outside +* minor change in variable usage +* Implemented a bson_only_mode flag for the TCP version of rosbridge; This allows you to switch to a full-duplex transmission of BSON messages and therefore eliminates the need for a base64 encoding of binary data; Use the new mode by starting:'roslaunch rosbridge_server rosbridge_tcp.launch bson_only_mode:=True' or passing '--bson_only_mode' to the rosbridge_tcp.py script +* Delay unregister to mitigate !138 +* Contributors: Andrew Blakey, Jihoon Lee, Nils Berg, Patrick Mania, Victor Lopez + +0.7.17 (2017-01-25) +------------------- +* adjust log level for security globs + Normal operation (i.e. no globs or successful verification of requests) is now silent, with illegal requests producing a warning. +* add missing import +* correct default values for security globs + also accept empty list as the default "do not check globs" value in addition to None. + Finally, append rosapi service glob after processing command line input so it's not overwritten +* Added services_glob to CallServices, added globs to rosbridge_tcp and rosbridge_udp, and other miscellaneous fixes. +* As per the suggestions of @T045T, fixed several typos, improved logging, and made some style fixes. +* Added new parameters for topic and service security. + Added 3 new parameters to rosapi and rosbridge_server which filter the + topics, services, and parameters broadcast by the server to match an + array of glob strings. +* Contributors: Eric, Nils Berg + +0.7.16 (2016-08-15) +------------------- +* Fixed deprecated code in pillow +* Contributors: vladrotea + +0.7.15 (2016-04-25) +------------------- +* changelog updated +* Contributors: Russell Toris + +0.7.14 (2016-02-11) +------------------- +* Another fix for code +* Replaced += with ''.join() for python code +* Default Protocol delay_between_messages = 0 + This prevents performance problems when multiple clients are subscribing to high frequency topics. + Fixes `#203 `_ +* Contributors: Matt Vollrath, kiloreux + +0.7.13 (2015-08-14) +------------------- +* Nevermind o_O +* Add test_depend too (just in case) +* Add dependency on python bson +* Get parameter at encode time +* Add flag for using the bson encoding +* revert comment regarding unpublisher +* avoiding racing condition +* Add bson encoding to the server side +* Fix catkin_lint issues +* don't unregister topic from rosbridge. It creates md5 sum warning.. #138 +* Contributors: David Lu, Jihoon Lee, Matt Vollrath, dwlee + +0.7.12 (2015-04-07) +------------------- +* use for test dependencies +* use rospy.resolve_name for namespaced service calls +* fix resolving namespaced service calls +* Contributors: Ramon Wijnands + +0.7.11 (2015-03-23) +------------------- + +0.7.10 (2015-02-25) +------------------- + +0.7.9 (2015-02-24) +------------------ + +0.7.8 (2015-01-16) +------------------ + +0.7.7 (2015-01-06) +------------------ + +0.7.6 (2014-12-26) +------------------ +* 0.7.5 +* update changelog +* 0.7.4 +* changelog updated +* 0.7.3 +* changelog updated +* 0.7.2 +* changelog updated +* 0.7.1 +* update changelog +* 0.7.0 +* changelog updated +* rewrite of advertise service +* cleanup init function +* matches original call_service +* matches original call_service +* service_request --> reuse of call_service (previously defined) +* stop_service --> unadvertise_service +* service_name --> service +* service_type --> type +* removed service_module +* request_id --> id +* Contributors: Jihoon Lee, Russell Toris + +0.7.5 (2014-12-26) +------------------ + +0.7.4 (2014-12-16) +------------------ + +0.7.3 (2014-12-15) +------------------ + +0.7.2 (2014-12-15) +------------------ +* 0.7.1 +* update changelog +* Contributors: Jihoon Lee + +0.7.1 (2014-12-09) +------------------ + +0.7.0 (2014-12-02) +------------------ +* rewrite of advertise service +* cleanup init function +* matches original call_service +* matches original call_service +* service_request --> reuse of call_service (previously defined) +* stop_service --> unadvertise_service +* service_name --> service +* service_type --> type +* removed service_module +* request_id --> id +* Contributors: Russell Toris + +0.6.8 (2014-11-05) +------------------ +* add a lock to calls to load_manifest - apparently, it's not thread safe + fixes #103 and #108 +* Contributors: Nils Berg + +0.6.7 (2014-10-22) +------------------ +* updated package manifests +* Contributors: Russell Toris + +0.6.6 (2014-10-21) +------------------ + +0.6.5 (2014-10-14) +------------------ +* 0.6.4 +* update changelog +* modify tests + less duplicated code, some other changes to (hopefully) improve reliability. Tested locally about 30 times without encountering any failures. +* Change the behavior of MessageHandler.transition() + Now reflects usage in the tests, i.e. a QueueMessageHandler only needs queue_length to be defined, not throttle_rate. +* 0.6.3 +* update change log +* install util python module to fix #128 +* Contributors: Jihoon Lee, Nils Berg + +0.6.4 (2014-10-08) +------------------ + +0.6.3 (2014-10-07) +------------------ +* install util python module to fix `#128 `_ +* Contributors: Jihoon Lee + +0.6.2 (2014-10-06) +------------------ +* Remove unused json imports; move json imports to utility + Fixes #7 +* Contributors: Graeme Yeates + +0.6.1 (2014-09-01) +------------------ +* Handle float infinity and NAN s +* Windows-related fix for PIL Image module import +* Fixed typo in raising type errors. +* something messed up indentation + not sure how that could happen, worked here. +* map Inf and NaN to null + JSON does not support Inf and NaN values. Currently they are just written into the JSON and JSON.parse on the client side will fail. Correct is to map them to null which will then be parsed correctly by JSON.parse on the client side. + The issue with that is that the shortcut for lists of floats might be impossible (maybe someone else with more experience in python comes up with something else?). Maybe something similar is necessary in the to_inst case, but I can not really test them. + Real world application is to process laser scans, they contain inf and nan values for some drivers if the measurements are invalid or out of range. +* Update .travis.yml and package.xml for rosbridge_library tests +* Put back unregister for the publisher and clarify the reconnect behavior + of the test case. The exponential backoff of the client causes hard to + understand timing of the events. + All specs passed locally on hydro: + SUMMARY + * RESULT: SUCCESS + * TESTS: 103 + * ERRORS: 0 + * FAILURES: 0 +* Add copyright notice to the file +* Remove extra whitespace +* Make the test more deterministic +* Remove circular dependency. +* Contributors: Achim Konigs, Alex Sorokin, Alexander Sorokin, Jonathan Wade, jon-weisz + +0.6.0 (2014-05-23) +------------------ +* Ensure that service name is a string + Closes `#104 `_ +* Contributors: Piyush Khandelwal + +0.5.4 (2014-04-17) +------------------ +* removing wrong import +* test case for fixed size of uint8 array +* uses regular expression to match uint8 array and char array. +* logerr when it fails while message_conversion +* Contributors: Jihoon Lee + +0.5.3 (2014-03-28) +------------------ +* use queue_size for publishers +* Contributors: Jon Binney + +0.5.2 (2014-03-14) +------------------ +* First attempt adding latching support for topic publishers +* merging changes of groovy-devel into hydro-devel +* adding missing dependency in rosbridge_library `#70 `_ +* Fixed wrong unicode encoding +* support publishing non-ascii letters +* Added error message on result=False + When call_service returns False as result, values contains the error message. +* added parameter lookup to rosbridge_tcp.py, modules where those are used, and default parameters to launch file; internal default-values still get used when launch-file does not provide them; internal defaults can be changed within rosbridge_tcp.py +* Merge branch 'experimental_branch' into new_features +* fix handling of partial/multiple/broken json by avoiding to pass nested json (without op-field) to rosbridge.. probably still needs more complex handling of incoming 'broken' json +* nested service not MiRoR related anymore +* added singleton for request-list; allows provider to send service response without specifying module and type, they get looked up when response is received via request_id +* fix for nested service responses - use ros_loader and message_conversion for populating an according instance +* use message_conversion in handle_servie_request +* snapshot for branch to show to genpy devs +* using float64 instead of std_msgs/Float64 lets scripts run fine.. ; next: fix with using std_msgs/Float64 --> need nested data field +* nested srv uses now message_conversion.extract_values +* adapted test scripted to ros_loader; (removed .srv from module_name +* use rosloader for finding service_class +* fixed calculation of fragment_count +* cleanup: files, notes, some code +* added message_field to allow client to control delay between messages from rosbridge +* added TODO: check if service successfully registered in ros +* .. +* .. +* added description of new opcodes +* tests, comments, description, .. +* tested rosbridge_websocket with new capabilities; websocket test scripts not working yet..; but new caps are working when using rosbridge_websocket and tcp2ws wrapper --> so only testscripts need to be fixed for websockets. +* updated websocket test service server and client script to use websocket +* updated websocket test service server script to use websocket +* added files to test new caps with websocket server +* feierabend.. morgen weiter mit server & client JSON-decoder, see notes +* fixed parsing of incomplete/multiple JSON in incoming buffer; so clients do not need to use an interval when sending to rosbridge +* only current changes; not yet done.. +* code cleanup, not yet finished..; rosbridge logging much cleaner now +* fixed test_server_defragment - recodegit status +* minor +* linuxonandroid +* fixed some parts; ..still better do some redesign for queueing of messages.. +* forced tcp_send to use queue and use delay between sends +* blocking behavior for service requests to non-ros; test-scripts use get-ip4 helper function; ..needs a lot cleanup before next steps.. +* need to implement server side blocking of multiple requests, to keep implementation of service provider as easy and simple as possible +* not finished +* some changes.. still needs several fixes +* unique request_ids +* fixed deserialization of multiple fragments in incoming-data; was caused by too short delay between socket-sends (<0.2 seconds); maybe only temp. fixed +* added fragment sorting to test-client and test-server +* message_size debugging; TODO: sort list of received fragments! ; make sure receive_buffers are big enough for fragment_size + header.. +* minor changes +* testing: service server fragmentsizes receive: 1 send: 1; client fragmentsize receive: 1; is working.. +* fixed an error that caused service_response to appear quoted as string once too often; should be ok now +* fragmentation basically working; service_server can request fragmented service_calls, service_client can request fragmented responses; fragmentation can be requested by adding fragmentation_size parameter to any message sent to rosbridge +* some code cleanup +* set service_request_timeout back to 60 seconds; had 2s from timeout_tests.. +* fixed example: non-ros_service_server.py to use only 1 socket; commented and structured code and comments in test-scripts +* some minor changes: comments, debug-output, .. +* added test script for non-ros_service_client calling service from non-ros_service_server +* added msg and srv files +* fixed (removed) dependency to beginner_tutorials for service_server test-scripts. beginner_tutorials package not needed anymore. +* behaviour on advertising existing service: replace service-provider, similar to ROS-groovy behaviour, see issues.. +* behaviour on advertising existing service: replace service-provider, similar to ROS-groovy behaviour, see issues.. +* removed obsolete test-scripts +* stop service added +* first working classes: service_server +* should use its own branch: service_server.py; add initial thoughts and code-base for developing ServiceServer capability +* fixed errors in protocol.py and defragmentation.py +* added test-scripts for defragmentation AND tcp-server +* change json imports to try to use ujson or simplejson +* change json imports to try to use ujson or simplejson; correct log_message to show length of content/data instead of overall length +* fixed variable name in finish() +* Clean up of defragmentation.py. +* add defragmentation capability +* merge with fuerte-devel +* add defragmentation capability +* commented out that problematic unregister line +* Contributors: Brandon Alexander, Jihoon Lee, Julian Cerruti, Kaijen Hsiao, Stefan Profanter, dave, furushchev, fxm-db, ipa-fxm, root, unknown + +0.5.1 (2013-10-31) +------------------ +* Implement multiple subscriptions to latched topics (fixes `#1 `_). +* generate more natural json for service call result +* add result field to service response +* Contributors: Siegfried-A. Gevatter Pujals, Takashi Ogura + +0.5.0 (2013-07-17) +------------------ +* 0.5.0 preparation for hydro release +* even more missing depends for unit tests +* more missing test packages +* missing depends added when running tests +* rostest now uses devel instead of install +* rostest added to package +* Contributors: Jihoon Lee, Russell Toris + +0.4.4 (2013-04-08) +------------------ + +0.4.3 (2013-04-03 08:24) +------------------------ + +0.4.2 (2013-04-03 08:12) +------------------------ +* eclipse projects removed +* Contributors: Russell Toris + +0.4.1 (2013-03-07) +------------------ +* adding message generation build dependency +* Contributors: Jihoon Lee + +0.4.0 (2013-03-05) +------------------ +* removing rostest +* Commenting out rostest +* Update rosbridge_library/package.xml + removed rospy +* Fixes "'int' is not iterable" bug. +* Adds test_all.test launch file. +* Error fix from wrong package name. +* Moves test package tests into rosbridge_library. + I learned about NOINSTALL for msg and srv generation in CMakeList. +* Resolves submodule issues. +* Uses only 1 .gitignore to avoid confusion. +* Merge pull request `#15 `_ from baalexander/remove_unregister + Removes buggy unregister call. +* Removes buggy unregister call. + Fixes Issue `#12 `_. +* Adds BSD license header to code files. + See Issue `#13 `_. +* Removing ultrajson from rosbridge. + If JSON parsing becomes a performance bottle neck, we can re-add it. +* Catkinizing rosbridge_library and server. +* PNG compression now creates a square RGB image padded with new-line characters +* Add stack dependencies and rosdeps. +* Collapse directory structure. +* Moved the packages inside a folder called rosbridge +* Initial commit of rosbridge_library +* Contributors: Austin Hendrix, Brandon Alexander, David Gossow, Jihoon Lee, Jonathan Mace, Russell Toris diff --git a/src/interface/rosbridge_suite/rosbridge_library/CMakeLists.txt b/src/interface/rosbridge_suite/rosbridge_library/CMakeLists.txt new file mode 100644 index 000000000..96a4fecda --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.5) +project(rosbridge_library) + +find_package(ament_cmake_ros REQUIRED) +find_package(ament_cmake_core REQUIRED) +find_package(ament_cmake_python REQUIRED) + +ament_python_install_package( + ${PROJECT_NAME} PACKAGE_DIR "src/${PROJECT_NAME}") + +ament_package() + +if (BUILD_TESTING) + find_package(ament_cmake_pytest REQUIRED) + + # TODO: Enable tests + # ament_add_pytest_test(test_capabilities "test/capabilities") + # ament_add_pytest_test(test_internal "test/internal") + # ament_add_pytest_test(test_services "test/internal/test_services.py") + ament_add_pytest_test(test_ros_loader "test/internal/test_ros_loader.py") + ament_add_pytest_test(test_message_conversion "test/internal/test_message_conversion.py") +endif() diff --git a/src/interface/rosbridge_suite/rosbridge_library/package.xml b/src/interface/rosbridge_suite/rosbridge_library/package.xml new file mode 100644 index 000000000..7583d85ae --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/package.xml @@ -0,0 +1,51 @@ + + + rosbridge_library + 1.3.1 + + The core rosbridge package, responsible for interpreting JSON andperforming + the appropriate ROS action, like subscribe, publish, call service, and + interact with params. + + + BSD + + http://ros.org/wiki/rosbridge_library + https://github.com/RobotWebTools/rosbridge_suite/issues + https://github.com/RobotWebTools/rosbridge_suite + + Jonathan Mace + Jihoon Lee + Foxglove + + ament_cmake + ament_cmake_ros + + python3-pil + python3-bson + + rclpy + python3-pil + rosidl_default_runtime + python3-bson + + rosbridge_test_msgs + actionlib_msgs + ament_cmake_pytest + builtin_interfaces + diagnostic_msgs + example_interfaces + geometry_msgs + nav_msgs + sensor_msgs + std_msgs + std_srvs + stereo_msgs + tf2_msgs + trajectory_msgs + visualization_msgs + + + ament_cmake + + diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/advertise.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/advertise.py new file mode 100644 index 000000000..7e2f95021 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/advertise.py @@ -0,0 +1,184 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# Copyright (c) 2014, Creativa 77 SRL +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import fnmatch + +from rosbridge_library.capability import Capability +from rosbridge_library.internal.publishers import manager + + +class Registration: + """Keeps track of how many times a client has requested to advertise + a publisher. + + A client could advertise and unadvertise a topic multiple times, and we + must make sure that the underlying publisher is only created and destroyed + at the appropriate moments + + """ + + def __init__(self, client_id, topic, node_handle): + # Initialise variables + self.client_id = client_id + self.topic = topic + self.clients = {} + self.node_handle = node_handle + + def unregister(self): + manager.unregister(self.client_id, self.topic) + + def register_advertisement(self, msg_type, adv_id=None, latch=False, queue_size=100): + # Register with the publisher manager, propagating any exception + manager.register( + self.client_id, + self.topic, + self.node_handle, + msg_type=msg_type, + latch=latch, + queue_size=queue_size, + ) + + self.clients[adv_id] = True + + def unregister_advertisement(self, adv_id=None): + if adv_id is None: + self.clients.clear() + elif adv_id in self.clients: + del self.clients[adv_id] + + def is_empty(self): + return len(self.clients) == 0 + + +class Advertise(Capability): + + advertise_msg_fields = [(True, "topic", str), (True, "type", str)] + unadvertise_msg_fields = [(True, "topic", str)] + + topics_glob = None + + def __init__(self, protocol): + # Call superclass constructor + Capability.__init__(self, protocol) + + # Register the operations that this capability provides + protocol.register_operation("advertise", self.advertise) + protocol.register_operation("unadvertise", self.unadvertise) + + # Initialize class variables + self._registrations = {} + + if protocol.parameters and "unregister_timeout" in protocol.parameters: + manager.unregister_timeout = protocol.parameters.get("unregister_timeout") + + def advertise(self, message): + # Pull out the ID + aid = message.get("id", None) + + self.basic_type_check(message, self.advertise_msg_fields) + topic = message["topic"] + msg_type = message["type"] + latch = message.get("latch", False) + queue_size = message.get("queue_size", 100) + + if Advertise.topics_glob is not None and Advertise.topics_glob: + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + match = False + for glob in Advertise.topics_glob: + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing advertisement...", + ) + match = True + break + if not match: + self.protocol.log( + "warn", + "No match found for topic, cancelling advertisement of: " + topic, + ) + return + else: + self.protocol.log("debug", "No topic security glob, not checking advertisement.") + + # Create the Registration if one doesn't yet exist + if topic not in self._registrations: + client_id = self.protocol.client_id + self._registrations[topic] = Registration(client_id, topic, self.protocol.node_handle) + + # Register, propagating any exceptions + self._registrations[topic].register_advertisement(msg_type, aid, latch, queue_size) + + def unadvertise(self, message): + # Pull out the ID + aid = message.get("id", None) + + self.basic_type_check(message, self.unadvertise_msg_fields) + topic = message["topic"] + + if Advertise.topics_glob is not None and Advertise.topics_glob: + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + match = False + for glob in Advertise.topics_glob: + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing unadvertisement...", + ) + match = True + break + if not match: + self.protocol.log( + "warn", + "No match found for topic, cancelling unadvertisement of: " + topic, + ) + return + else: + self.protocol.log("debug", "No topic security glob, not checking unadvertisement.") + + # Now unadvertise the topic + if topic not in self._registrations: + return + self._registrations[topic].unregister_advertisement(aid) + + # Check if the registration is now finished with + if self._registrations[topic].is_empty(): + self._registrations[topic].unregister() + del self._registrations[topic] + + def finish(self): + for registration in self._registrations.values(): + registration.unregister() + self._registrations.clear() + self.protocol.unregister_operation("advertise") + self.protocol.unregister_operation("unadvertise") diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py new file mode 100644 index 000000000..a1db57ed5 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/advertise_service.py @@ -0,0 +1,141 @@ +import fnmatch + +import rclpy +from rclpy.callback_groups import ReentrantCallbackGroup +from rosbridge_library.capability import Capability +from rosbridge_library.internal import message_conversion +from rosbridge_library.internal.ros_loader import get_service_class + + +class AdvertisedServiceHandler: + + id_counter = 1 + + def __init__(self, service_name, service_type, protocol): + self.request_futures = {} + self.service_name = service_name + self.service_type = service_type + self.protocol = protocol + # setup the service + self.service_handle = protocol.node_handle.create_service( + get_service_class(service_type), + service_name, + self.handle_request, + callback_group=ReentrantCallbackGroup(), # https://github.com/ros2/rclpy/issues/834#issuecomment-961331870 + ) + + def next_id(self): + id = self.id_counter + self.id_counter += 1 + return id + + async def handle_request(self, req, res): + # generate a unique ID + request_id = "service_request:" + self.service_name + ":" + str(self.next_id()) + + future = rclpy.task.Future() + self.request_futures[request_id] = future + + # build a request to send to the external client + request_message = { + "op": "call_service", + "id": request_id, + "service": self.service_name, + "args": message_conversion.extract_values(req), + } + self.protocol.send(request_message) + + try: + return await future + finally: + del self.request_futures[request_id] + + def handle_response(self, request_id, res): + """ + Called by the ServiceResponse capability to handle a service response from the external client. + """ + if request_id in self.request_futures: + self.request_futures[request_id].set_result(res) + else: + self.protocol.log( + "warning", f"Received service response for unrecognized id: {request_id}" + ) + + def graceful_shutdown(self): + """ + Signal the AdvertisedServiceHandler to shutdown + + Using this, rather than just node_handle.destroy_service, allows us + time to stop any active service requests, ending their busy wait + loops. + """ + if self.request_futures: + incomplete_ids = ", ".join(self.request_futures.keys()) + self.protocol.log( + "warning", + f"Service {self.service_name} was unadvertised with a service call in progress, " + f"aborting service calls with request IDs {incomplete_ids}", + ) + for future in self.request_futures.values(): + future.set_exception(RuntimeError(f"Service {self.service_name} was unadvertised")) + self.protocol.node_handle.destroy_service(self.service_handle) + + +class AdvertiseService(Capability): + services_glob = None + + advertise_service_msg_fields = [(True, "service", str), (True, "type", str)] + + def __init__(self, protocol): + # Call superclass constructor + Capability.__init__(self, protocol) + + # Register the operations that this capability provides + protocol.register_operation("advertise_service", self.advertise_service) + + def advertise_service(self, message): + # Typecheck the args + self.basic_type_check(message, self.advertise_service_msg_fields) + + # parse the incoming message + service_name = message["service"] + + if AdvertiseService.services_glob is not None and AdvertiseService.services_glob: + self.protocol.log( + "debug", + "Service security glob enabled, checking service: " + service_name, + ) + match = False + for glob in AdvertiseService.services_glob: + if fnmatch.fnmatch(service_name, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing service advertisement...", + ) + match = True + break + if not match: + self.protocol.log( + "warn", + "No match found for service, cancelling service advertisement for: " + + service_name, + ) + return + else: + self.protocol.log( + "debug", "No service security glob, not checking service advertisement." + ) + + # check for an existing entry + if service_name in self.protocol.external_service_list.keys(): + self.protocol.log( + "warn", "Duplicate service advertised. Overwriting %s." % service_name + ) + self.protocol.external_service_list[service_name].graceful_shutdown() + del self.protocol.external_service_list[service_name] + + # setup and store the service information + service_type = message["type"] + service_handler = AdvertisedServiceHandler(service_name, service_type, self.protocol) + self.protocol.external_service_list[service_name] = service_handler + self.protocol.log("info", "Advertised service %s." % service_name) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/call_service.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/call_service.py new file mode 100644 index 000000000..3628a9268 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/call_service.py @@ -0,0 +1,151 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import fnmatch +from functools import partial +from threading import Thread + +from rosbridge_library.capability import Capability +from rosbridge_library.internal.services import ServiceCaller + + +class CallService(Capability): + + call_service_msg_fields = [ + (True, "service", str), + (False, "fragment_size", (int, type(None))), + (False, "compression", str), + ] + + services_glob = None + + def __init__(self, protocol): + # Call superclas constructor + Capability.__init__(self, protocol) + + # Register the operations that this capability provides + call_services_in_new_thread = protocol.node_handle.get_parameter( + "call_services_in_new_thread" + ).get_parameter_value() + if call_services_in_new_thread: + # Calls the service in a separate thread so multiple services can be processed simultaneously. + protocol.node_handle.get_logger().info("Calling services in new thread") + protocol.register_operation( + "call_service", lambda msg: Thread(target=self.call_service, args=(msg,)).start() + ) + else: + # Calls the service in this thread, so services block and must be processed sequentially. + protocol.node_handle.get_logger().info("Calling services in existing thread") + protocol.register_operation("call_service", self.call_service) + + def call_service(self, message): + # Pull out the ID + cid = message.get("id", None) + + # Typecheck the args + self.basic_type_check(message, self.call_service_msg_fields) + + # Extract the args + service = message["service"] + fragment_size = message.get("fragment_size", None) + compression = message.get("compression", "none") + args = message.get("args", []) + + if CallService.services_glob is not None and CallService.services_glob: + self.protocol.log( + "debug", "Service security glob enabled, checking service: " + service + ) + match = False + for glob in CallService.services_glob: + if fnmatch.fnmatch(service, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing service call...", + ) + match = True + break + if not match: + self.protocol.log( + "warn", + "No match found for service, cancelling service call for: " + service, + ) + return + else: + self.protocol.log("debug", "No service security glob, not checking service call.") + + # Check for deprecated service ID, eg. /rosbridge/topics#33 + cid = extract_id(service, cid) + + # Create the callbacks + s_cb = partial(self._success, cid, service, fragment_size, compression) + e_cb = partial(self._failure, cid, service) + + # Run service caller in the same thread. + ServiceCaller(trim_servicename(service), args, s_cb, e_cb, self.protocol.node_handle).run() + + def _success(self, cid, service, fragment_size, compression, message): + outgoing_message = { + "op": "service_response", + "service": service, + "values": message, + "result": True, + } + if cid is not None: + outgoing_message["id"] = cid + # TODO: fragmentation, compression + self.protocol.send(outgoing_message) + + def _failure(self, cid, service, exc): + self.protocol.log("error", "call_service %s: %s" % (type(exc).__name__, str(exc)), cid) + # send response with result: false + outgoing_message = { + "op": "service_response", + "service": service, + "values": str(exc), + "result": False, + } + if cid is not None: + outgoing_message["id"] = cid + self.protocol.send(outgoing_message) + + +def trim_servicename(service): + if "#" in service: + return service[: service.find("#")] + return service + + +def extract_id(service, cid): + if cid is not None: + return cid + elif "#" in service: + return service[service.find("#") + 1 :] diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py new file mode 100644 index 000000000..1757a1179 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/defragmentation.py @@ -0,0 +1,210 @@ +import threading +from datetime import datetime + +from rosbridge_library.capability import Capability + + +class ReceivedFragments: + """ + Singleton class to hold lists of received fragments in one 'global' object + """ + + class __impl: + """Implementation of the singleton interface""" + + def spam(self): + """Test method, return singleton id""" + return id(self) + + __instance = None + # List of defragmentation instances + # Format: + # { + # <> : { + # "timestamp_last_append" : <>, + # "total" : <>, + # "fragment_list" : { + # <>: <>, + # <>: <>, + # ... + # } + # }, + # ... + lists = {} + + def __init__(self): + """Create singleton instance""" + if ReceivedFragments.__instance is None: + ReceivedFragments.__instance = ReceivedFragments.__impl() + self.lists = {} + + self.__dict__["_ReceivedFragments__instance"] = ReceivedFragments.__instance + + def __getattr__(self, attr): + """Delegate access to implementation""" + return getattr(self.__instance, attr) + + def __setattr__(self, attr, value): + """Delegate access to implementation""" + return setattr(self.__instance, attr, value) + + +class Defragment(Capability, threading.Thread): + + fragment_timeout = 600 + opcode = "fragment" + global received_fragments + + protocol = None + + def __init__(self, protocol): + Capability.__init__(self, protocol) + + self.protocol = protocol + + # populate parameters + if self.protocol.parameters is not None: + self.fragment_timeout = self.protocol.parameters["fragment_timeout"] + + protocol.register_operation(self.opcode, self.defragment) + + self.received_fragments = ReceivedFragments().lists + threading.Thread.__init__(self) + + # defragment() does: + # 1) take any incoming message with op-code "fragment" + # 2) check all existing fragment lists for time out # could be done by a thread but should be okay this way: + # 2.a) remove timed out lists (only if new fragment is not for this list) # - checking whenever a new fragment is received should suffice + # 3) create a new fragment list for new message ids # to have control over growth of fragment lists + # 3.a) check message fields + # 3.b) append the new fragment to 'the' list + # 3.c) add time stamp (last_fragment_appended) to 'this' list + # 4) check if the list of current fragment (message id) is complete + # 4.a) reconstruct the original message by concatenating the fragments + # 4.b) pass the reconstructed message string to protocol.incoming() # protocol.incoming is checking message fields by itself, so no need to do this before passing the reconstructed message to protocol + # 4.c) remove the fragment list to free up memory + def defragment(self, message): + now = datetime.now() + + if self.received_fragments is not None: + for id in self.received_fragments.keys(): + time_diff = now - self.received_fragments[id]["timestamp_last_append"] + if ( + time_diff.total_seconds() > self.fragment_timeout + and not self.received_fragments[id]["is_reconstructing"] + ): + log_msg = ["fragment list ", str(id), " timed out.."] + + if message["id"] != id: + log_msg.append(" -> removing it..") + del self.received_fragments[id] + else: + log_msg.extend([" -> but we're just about to add fragment #"]) + log_msg.extend([str(message.get("num")), " of "]) + log_msg.extend([str(self.received_fragments[message.get("id")]["total"])]) + log_msg.extend([" ..keeping the list"]) + self.protocol.log("warning", "".join(log_msg)) + + msg_opcode = message.get("op") + msg_id = message.get("id") + msg_num = message.get("num") + msg_total = message.get("total") + msg_data = message.get("data") + + # Abort if any message field is missing + if None in (msg_opcode, msg_id, msg_num, msg_total, msg_data): + self.protocol.log("error", "received invalid fragment!") + return + + log_msg = "fragment for messageID: " + str(msg_id) + " received." + self.protocol.log("debug", log_msg) + + # Create fragment container if none exists yet + if msg_id not in self.received_fragments.keys(): + self.received_fragments[msg_id] = { + "is_reconstructing": False, + "total": message["total"], + "timestamp_last_append": now, + "fragment_list": {}, + } + log_msg = "opened new fragment list for messageID " + str(msg_id) + self.protocol.log("debug", log_msg) + + # print "received fragments:", len(self.received_fragments[msg_id]["fragment_list"].keys()) + + # Add fragment to fragment container's list if not already in list + if ( + (msg_num not in self.received_fragments[msg_id]["fragment_list"].keys()) + and msg_num <= self.received_fragments[msg_id]["total"] + and msg_total == self.received_fragments[msg_id]["total"] + ): + self.received_fragments[msg_id]["fragment_list"][msg_num] = msg_data + self.received_fragments[msg_id]["timestamp_last_append"] = now + log_msg = ["appended fragment #" + str(msg_num)] + log_msg.extend( + [ + " (total: ", + str(msg_total), + ") to fragment list for messageID ", + str(msg_id), + ] + ) + self.protocol.log("debug", "".join(log_msg)) + else: + log_msg = "error while trying to append fragment " + str(msg_num) + self.protocol.log("error", log_msg) + return + + received_all_fragments = False + existing_fragments = len(self.received_fragments[msg_id]["fragment_list"]) + announced_total = self.received_fragments[msg_id]["total"] + + # Make sure total number of fragments received + if existing_fragments == announced_total: + log_msg = ["enough/all fragments for messageID " + str(msg_id) + " received"] + log_msg.extend([" [", str(existing_fragments), "]"]) + log_msg = "".join(log_msg) + self.protocol.log("debug", log_msg) + # Check each fragment matches up + received_all_fragments = True + for i in range(0, announced_total): + if i not in self.received_fragments[msg_id]["fragment_list"]: + received_all_fragments = False + log_msg = "fragment #" + str(i) + log_msg += " for messageID " + str(msg_id) + " is missing! " + self.protocol.log("error", log_msg) + + self.received_fragments[msg_id]["is_reconstructing"] = received_all_fragments + + if received_all_fragments: + log_msg = "reconstructing original message " + str(msg_id) + self.protocol.log("debug", log_msg) + + # Reconstruct the message + reconstructed_msg = "".join(self.received_fragments[msg_id]["fragment_list"].values()) + + log_msg = ["reconstructed original message:\n"] + log_msg.append(reconstructed_msg) + log_msg = "".join(log_msg) + self.protocol.log("debug", log_msg) + + duration = datetime.now() - now + + # Pass the reconstructed message to rosbridge + self.protocol.incoming(reconstructed_msg) + log_msg = ["reconstructed message (ID:" + str(msg_id) + ") from "] + log_msg.extend([str(msg_total), " fragments. "]) + # cannot access msg.data if message is a service_response or else! + # log_msg += "[message length: " + str(len(str(json.loads(reconstructed_msg)["msg"]["data"]))) +"]" + log_msg.extend(["[duration: ", str(duration.total_seconds()), " s]"]) + log_msg = "".join(log_msg) + self.protocol.log("info", log_msg) + + # Remove fragmentation container + del self.received_fragments[msg_id] + log_msg = "removed fragment list for messageID " + str(msg_id) + self.protocol.log("debug", log_msg) + + def finish(self): + self.received_fragments = None + self.protocol.unregister_operation("fragment") diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py new file mode 100644 index 000000000..dceec2b0d --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/fragmentation.py @@ -0,0 +1,116 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import math + +from rosbridge_library.capability import Capability + + +class Fragmentation(Capability): + """The Fragmentation capability doesn't define any incoming operation + handlers, but provides methods to fragment outgoing messages""" + + fragmentation_seed = 0 + + def __init__(self, protocol): + # Call superclass constructor + Capability.__init__(self, protocol) + + def fragment(self, message, fragment_size, mid=None): + """Serializes the provided message, then splits the serialized + message according to fragment_size, then sends the fragments. + + If the size of the message is less than the fragment size, then + the original message is returned rather than a single fragment + + Since fragmentation is typically only used for very large messages, + this method returns a generator for fragments rather than a list + + Keyword Arguments + message -- the message dict object to be fragmented + fragment_size -- the max size for the fragments + mid -- (optional) if provided, the fragment messages + will be given this id. Otherwise an id will be auto-generated. + + Returns a generator of message dict objects representing the fragments + """ + # All fragmented messages need an ID so they can be reconstructed + if mid is None: + mid = self.fragmentation_seed + self.fragmentation_seed = self.fragmentation_seed + 1 + + serialized = self.protocol.serialize(message, mid) + + if serialized is None: + return [] + + message_length = len(serialized) + if message_length <= fragment_size: + return [message] + + expected_duration = int( + math.ceil(math.ceil(message_length / float(fragment_size))) + * self.protocol.delay_between_messages + ) + + log_msg = ( + "sending " + + str(int(math.ceil(message_length / float(fragment_size)))) + + " parts [fragment size: " + + str(fragment_size) + + "; expected duration: ~" + + str(expected_duration) + + "s]" + ) + self.protocol.log("info", log_msg) + + return self._fragment_generator(serialized, fragment_size, mid) + + def _fragment_generator(self, msg, size, mid): + """Returns a generator of fragment messages""" + total = ((len(msg) - 1) / size) + 1 + n = 0 + for i in range(0, len(msg), size): + fragment = msg[i : i + size] + yield self._create_fragment(fragment, n, total, mid) + n = n + 1 + + def _create_fragment(self, fragment, num, total, mid): + """Given a string fragment of the original message, creates + the appropriate fragment message""" + return { + "op": "fragment", + "id": mid, + "data": fragment, + "num": num, + "total": total, + } diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/publish.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/publish.py new file mode 100644 index 000000000..d794ef42a --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/publish.py @@ -0,0 +1,113 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# Copyright (c) 2014, Creativa 77 SRL +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import fnmatch + +from rosbridge_library.capability import Capability +from rosbridge_library.internal.publishers import manager + + +class Publish(Capability): + + publish_msg_fields = [(True, "topic", str)] + + topics_glob = None + + def __init__(self, protocol): + # Call superclass constructor + Capability.__init__(self, protocol) + + # Register the operations that this capability provides + protocol.register_operation("publish", self.publish) + + # Save the topics that are published on for the purposes of unregistering + self._published = {} + + if protocol.parameters and "unregister_timeout" in protocol.parameters: + manager.unregister_timeout = protocol.parameters.get("unregister_timeout") + + def publish(self, message): + # Do basic type checking + self.basic_type_check(message, self.publish_msg_fields) + topic = message["topic"] + latch = message.get("latch", False) + queue_size = message.get("queue_size", 100) + + if Publish.topics_glob is not None and Publish.topics_glob: + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + match = False + for glob in Publish.topics_glob: + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing publish...", + ) + match = True + break + if not match: + self.protocol.log( + "warn", "No match found for topic, cancelling publish to: " + topic + ) + return + else: + self.protocol.log("debug", "No topic security glob, not checking publish.") + + # Register as a publishing client, propagating any exceptions + client_id = self.protocol.client_id + manager.register( + client_id, + topic, + self.protocol.node_handle, + latch=latch, + queue_size=queue_size, + ) + self._published[topic] = True + + # Get the message if one was provided + msg = message.get("msg", {}) + + # Publish the message + manager.publish( + client_id, + topic, + msg, + self.protocol.node_handle, + latch=latch, + queue_size=queue_size, + ) + + def finish(self): + client_id = self.protocol.client_id + for topic in self._published: + manager.unregister(client_id, topic) + self._published.clear() diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/service_response.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/service_response.py new file mode 100644 index 000000000..e54c846dd --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/service_response.py @@ -0,0 +1,41 @@ +from rosbridge_library.capability import Capability +from rosbridge_library.internal import message_conversion, ros_loader + + +class ServiceResponse(Capability): + + service_response_msg_fields = [ + (True, "service", str), + (False, "id", str), + (False, "values", dict), + (True, "result", bool), + ] + + def __init__(self, protocol): + # Call superclass constructor + Capability.__init__(self, protocol) + + # Register the operations that this capability provides + protocol.register_operation("service_response", self.service_response) + + def service_response(self, message): + # Typecheck the args + self.basic_type_check(message, self.service_response_msg_fields) + + # check for the service + service_name = message["service"] + if service_name in self.protocol.external_service_list: + service_handler = self.protocol.external_service_list[service_name] + # parse the message + request_id = message["id"] + values = message["values"] + # create a message instance + resp = ros_loader.get_service_response_instance(service_handler.service_type) + message_conversion.populate_instance(values, resp) + # pass along the response + service_handler.handle_response(request_id, resp) + else: + self.protocol.log( + "error", + "Service %s has not been advertised via rosbridge." % service_name, + ) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py new file mode 100644 index 000000000..61303d132 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/subscribe.py @@ -0,0 +1,337 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import fnmatch +from functools import partial +from threading import Lock + +from rosbridge_library.capability import Capability +from rosbridge_library.internal.pngcompression import encode as encode_png +from rosbridge_library.internal.subscribers import manager +from rosbridge_library.internal.subscription_modifiers import MessageHandler + +try: + from ujson import dumps as encode_json +except ImportError: + try: + from simplejson import dumps as encode_json + except ImportError: + from json import dumps as encode_json + + +class Subscription: + """Keeps track of the clients multiple calls to subscribe. + + Chooses the most appropriate settings to send messages""" + + def __init__(self, client_id, topic, publish, node_handle): + """Create a subscription for the specified client on the specified + topic, with callback publish + + Keyword arguments: + client_id -- the ID of the client making this subscription + topic -- the name of the topic to subscribe to + publish -- the callback function for incoming messages + node_handle -- Handle to a rclpy node to create the publisher. + + """ + self.client_id = client_id + self.topic = topic + self.publish = publish + self.node_handle = node_handle + + self.clients = {} + + self.handler = MessageHandler(None, self._publish) + self.handler_lock = Lock() + self.update_params() + + def unregister(self): + """Unsubscribes this subscription and cleans up resources""" + manager.unsubscribe(self.client_id, self.topic) + with self.handler_lock: + self.handler.finish(block=False) + self.clients.clear() + + def subscribe( + self, + sid=None, + msg_type=None, + throttle_rate=0, + queue_length=0, + fragment_size=None, + compression="none", + ): + """Add another client's subscription request + + If there are multiple calls to subscribe, the values actually used for + queue_length, fragment_size, compression and throttle_rate are + chosen to encompass all subscriptions' requirements + + Keyword arguments: + sid -- the subscription id from the client + msg_type -- the type of the message to subscribe to + throttle_rate -- the minimum time (in ms) allowed between messages + being sent. If multiple subscriptions, the lower of these is used + queue_length -- the number of messages that can be buffered. If + multiple subscriptions, the lower of these is used + fragment_size -- None if no fragmentation, or the maximum length of + allowed outgoing messages + compression -- "none" if no compression, or some other value if + compression is to be used (current valid values are 'png') + + """ + + client_details = { + "throttle_rate": throttle_rate, + "queue_length": queue_length, + "fragment_size": fragment_size, + "compression": compression, + } + + self.clients[sid] = client_details + + self.update_params() + + raw = compression == "cbor-raw" + + # Subscribe with the manager. This will propagate any exceptions + manager.subscribe( + self.client_id, + self.topic, + self.on_msg, + self.node_handle, + msg_type=msg_type, + raw=raw, + ) + + def unsubscribe(self, sid=None): + """Unsubscribe this particular client's subscription + + Keyword arguments: + sid -- the individual subscription id. If None, all are unsubscribed + + """ + if sid is None: + self.clients.clear() + elif sid in self.clients: + del self.clients[sid] + + if not self.is_empty(): + self.update_params() + + def is_empty(self): + """Return true if there are no subscriptions currently""" + return len(self.clients) == 0 + + def _publish(self, message): + """Internal method to propagate published messages to the registered + publish callback""" + self.publish(message, self.fragment_size, self.compression) + + def on_msg(self, msg): + """Raw callback called by subscription manager for all incoming + messages. + + Incoming messages are passed to the message handler which may drop, + buffer, or propagate the message + + """ + with self.handler_lock: + self.handler.handle_message(msg) + + def update_params(self): + """Determine the 'lowest common denominator' params to satisfy all + subscribed clients.""" + if len(self.clients) == 0: + self.throttle_rate = 0 + self.queue_length = 0 + self.fragment_size = None + self.compression = "none" + return + + def f(fieldname): + return [x[fieldname] for x in self.clients.values()] + + self.throttle_rate = min(f("throttle_rate")) + self.queue_length = min(f("queue_length")) + frags = [x for x in f("fragment_size") if x is not None] + if frags == []: + self.fragment_size = None + else: + self.fragment_size = min(frags) + + self.compression = "none" + if "png" in f("compression"): + self.compression = "png" + if "cbor" in f("compression"): + self.compression = "cbor" + if "cbor-raw" in f("compression"): + self.compression = "cbor-raw" + + with self.handler_lock: + self.handler = self.handler.set_throttle_rate(self.throttle_rate) + self.handler = self.handler.set_queue_length(self.queue_length) + + +class Subscribe(Capability): + + subscribe_msg_fields = [ + (True, "topic", str), + (False, "type", str), + (False, "throttle_rate", int), + (False, "fragment_size", int), + (False, "queue_length", int), + (False, "compression", str), + ] + unsubscribe_msg_fields = [(True, "topic", str)] + + topics_glob = None + + def __init__(self, protocol): + # Call superclass constructor + Capability.__init__(self, protocol) + + # Register the operations that this capability provides + protocol.register_operation("subscribe", self.subscribe) + protocol.register_operation("unsubscribe", self.unsubscribe) + + self._subscriptions = {} + + def subscribe(self, msg): + # Pull out the ID + sid = msg.get("id", None) + + # Check the args + self.basic_type_check(msg, self.subscribe_msg_fields) + + # Make the subscription + topic = msg["topic"] + + if Subscribe.topics_glob is not None and Subscribe.topics_glob: + self.protocol.log("debug", "Topic security glob enabled, checking topic: " + topic) + match = False + for glob in Subscribe.topics_glob: + if fnmatch.fnmatch(topic, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing subscription...", + ) + match = True + break + if not match: + self.protocol.log( + "warn", + "No match found for topic, cancelling subscription to: " + topic, + ) + return + else: + self.protocol.log("debug", "No topic security glob, not checking subscription.") + + if topic not in self._subscriptions: + client_id = self.protocol.client_id + cb = partial(self.publish, topic) + self._subscriptions[topic] = Subscription( + client_id, topic, cb, self.protocol.node_handle + ) + + # Register the subscriber + subscribe_args = { + "sid": sid, + "msg_type": msg.get("type", None), + "throttle_rate": msg.get("throttle_rate", 0), + "fragment_size": msg.get("fragment_size", None), + "queue_length": msg.get("queue_length", 0), + "compression": msg.get("compression", "none"), + } + self._subscriptions[topic].subscribe(**subscribe_args) + + self.protocol.log("info", "Subscribed to %s" % topic) + + def unsubscribe(self, msg): + # Pull out the ID + sid = msg.get("id", None) + + self.basic_type_check(msg, self.unsubscribe_msg_fields) + + topic = msg["topic"] + + if topic not in self._subscriptions: + return + self._subscriptions[topic].unsubscribe(sid) + + if self._subscriptions[topic].is_empty(): + self._subscriptions[topic].unregister() + del self._subscriptions[topic] + + self.protocol.log("info", "Unsubscribed from %s" % topic) + + def publish(self, topic, message, fragment_size=None, compression="none"): + """Publish a message to the client + + Keyword arguments: + topic -- the topic to publish the message on + message -- a ROS message wrapped by OutgoingMessage + fragment_size -- (optional) fragment the serialized message into msgs + with payloads not greater than this value + compression -- (optional) compress the message. valid values are + 'png' and 'none' + + """ + # TODO: fragmentation, proper ids + + outgoing_msg = {"op": "publish", "topic": topic} + if compression == "png": + outgoing_msg["msg"] = message.get_json_values() + outgoing_msg_dumped = encode_json(outgoing_msg) + outgoing_msg = {"op": "png", "data": encode_png(outgoing_msg_dumped)} + elif compression == "cbor": + outgoing_msg = message.get_cbor(outgoing_msg) + elif compression == "cbor-raw": + (secs, nsecs) = self.protocol.node_handle.get_clock().now().seconds_nanoseconds() + outgoing_msg["msg"] = { + "secs": secs, + "nsecs": nsecs, + "bytes": message.message, + } + outgoing_msg = message.get_cbor_raw(outgoing_msg) + else: + outgoing_msg["msg"] = message.get_json_values() + + self.protocol.send(outgoing_msg, compression=compression) + + def finish(self): + for subscription in self._subscriptions.values(): + subscription.unregister() + self._subscriptions.clear() + self.protocol.unregister_operation("subscribe") + self.protocol.unregister_operation("unsubscribe") diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py new file mode 100644 index 000000000..ba3d738e1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capabilities/unadvertise_service.py @@ -0,0 +1,63 @@ +import fnmatch + +from rosbridge_library.capability import Capability + + +class UnadvertiseService(Capability): + + # unadvertise_service_msg_fields = [(True, "service", (str, unicode))] + + services_glob = None + + def __init__(self, protocol): + # Call superclass constructor + Capability.__init__(self, protocol) + + # Register the operations that this capability provides + protocol.register_operation("unadvertise_service", self.unadvertise_service) + + def unadvertise_service(self, message): + # parse the message + service_name = message["service"] + + if UnadvertiseService.services_glob is not None and UnadvertiseService.services_glob: + self.protocol.log( + "debug", + "Service security glob enabled, checking service: " + service_name, + ) + match = False + for glob in UnadvertiseService.services_glob: + if fnmatch.fnmatch(service_name, glob): + self.protocol.log( + "debug", + "Found match with glob " + glob + ", continuing service unadvertisement...", + ) + match = True + break + if not match: + self.protocol.log( + "warn", + "No match found for service, cancelling service unadvertisement for: " + + service_name, + ) + return + else: + self.protocol.log( + "debug", + "No service security glob, not checking service unadvertisement...", + ) + + # unregister service in ROS + if service_name in self.protocol.external_service_list.keys(): + self.protocol.external_service_list[service_name].graceful_shutdown() + self.protocol.external_service_list[service_name].service_handle.shutdown( + "Unadvertise request." + ) + del self.protocol.external_service_list[service_name] + self.protocol.log("info", "Unadvertised service %s." % service_name) + else: + self.protocol.log( + "error", + "Service %s has not been advertised via rosbridge, can't unadvertise." + % service_name, + ) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capability.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capability.py new file mode 100644 index 000000000..5415b719e --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/capability.py @@ -0,0 +1,110 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from rosbridge_library.internal.exceptions import ( + InvalidArgumentException, + MissingArgumentException, +) + + +class Capability: + """Handles the operation-specific logic of a rosbridge message + + May define one or more opcodes to handle, for example 'publish' or + 'call_service' + + Each connected client receives its own capability instance, which are + managed by the client's own protocol instance. + + Protocol.send() is available to send messages back to the client. + + """ + + def __init__(self, protocol): + """Abstract class constructor. All capabilities require a handle to + the containing protocol. + + Keyword arguments: + protocol -- the protocol instance for this capability instance + + """ + self.protocol = protocol + + def handle_message(self, message): + """Handle an incoming message. + + Called by the protocol after having already checked the message op code + + Keyword arguments: + message -- the incoming message, deserialized into a dictionary + + """ + pass + + def finish(self): + """Notify this capability that the client is finished and that it's + time to free up resources.""" + pass + + def basic_type_check(self, msg, types_info): + """Performs basic typechecking on fields in msg. + + Keyword arguments: + msg -- a message, deserialized into a dictoinary + types_info -- a list of tuples (mandatory, fieldname, fieldtype) where + mandatory - boolean, is the field mandatory + fieldname - the name of the field in the message + fieldtypes - the expected python type of the field or list of types + + Throws: + MissingArgumentException -- if a field is mandatory but not present in + the message + InvalidArgumentException -- if a field is present but not of the type + specified by fieldtype + + """ + for mandatory, fieldname, fieldtypes in types_info: + if mandatory and fieldname not in msg: + raise MissingArgumentException( + "Expected a %s field but none was found." % fieldname + ) + elif fieldname in msg: + if not isinstance(fieldtypes, tuple): + fieldtypes = (fieldtypes,) + valid = False + for typ in fieldtypes: + if isinstance(msg[fieldname], typ): + valid = True + if not valid: + raise InvalidArgumentException( + f"Expected field {fieldname} to be one of {fieldtypes}. Invalid value: {msg[fieldname]}" + ) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/cbor_conversion.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/cbor_conversion.py new file mode 100644 index 000000000..3e2128771 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/cbor_conversion.py @@ -0,0 +1,102 @@ +import struct + +try: + from cbor import Tag +except ImportError: + from rosbridge_library.util.cbor import Tag + + +LIST_TYPES = [list, tuple] +INT_TYPES = [ + "byte", + "char", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", +] +FLOAT_TYPES = ["float32", "float64"] +STRING_TYPES = ["string"] +BOOL_TYPES = ["bool"] +TIME_TYPES = ["time", "duration"] +BOOL_ARRAY_TYPES = ["bool[]"] +BYTESTREAM_TYPES = ["uint8[]", "char[]"] + +# Typed array tags according to +# Always encode to little-endian variant, for now. +TAGGED_ARRAY_FORMATS = { + "uint16[]": (69, "<{}H"), + "uint32[]": (70, "<{}I"), + "uint64[]": (71, "<{}Q"), + "byte[]": (72, "{}b"), + "int8[]": (72, "{}b"), + "int16[]": (77, "<{}h"), + "int32[]": (78, "<{}i"), + "int64[]": (79, "<{}q"), + "float32[]": (85, "<{}f"), + "float64[]": (86, "<{}d"), +} + + +def extract_cbor_values(msg): + """Extract a dictionary of CBOR-friendly values from a ROS message. + + Primitive values will be casted to specific Python primitives. + + Typed arrays will be tagged and packed into byte arrays. + """ + out = {} + for slot, slot_type in zip(msg.__slots__, msg._slot_types): + val = getattr(msg, slot) + + # string + if slot_type in STRING_TYPES: + out[slot] = str(val) + + # bool + elif slot_type in BOOL_TYPES: + out[slot] = bool(val) + + # integers + elif slot_type in INT_TYPES: + out[slot] = int(val) + + # floats + elif slot_type in FLOAT_TYPES: + out[slot] = float(val) + + # time/duration + elif slot_type in TIME_TYPES: + out[slot] = { + "secs": int(val.secs), + "nsecs": int(val.nsecs), + } + + # byte array + elif slot_type in BYTESTREAM_TYPES: + out[slot] = bytes(val) + + # bool array + elif slot_type in BOOL_ARRAY_TYPES: + out[slot] = [bool(i) for i in val] + + # numeric arrays + elif slot_type in TAGGED_ARRAY_FORMATS: + tag, fmt = TAGGED_ARRAY_FORMATS[slot_type] + fmt_to_length = fmt.format(len(val)) + packed = struct.pack(fmt_to_length, *val) + out[slot] = Tag(tag=tag, value=packed) + + # array of messages + elif type(val) in LIST_TYPES: + out[slot] = [extract_cbor_values(i) for i in val] + + # message + else: + out[slot] = extract_cbor_values(val) + + return out diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/exceptions.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/exceptions.py new file mode 100644 index 000000000..3f04a941c --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/exceptions.py @@ -0,0 +1,39 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +class InvalidArgumentException(Exception): + pass + + +class MissingArgumentException(Exception): + pass diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/message_conversion.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/message_conversion.py new file mode 100644 index 000000000..3355a11f6 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/message_conversion.py @@ -0,0 +1,411 @@ +#!/usr/bin/env python3 +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import array +import math +import re +from base64 import standard_b64decode, standard_b64encode + +import numpy as np +from rcl_interfaces.msg import Parameter +from rclpy.clock import ROSClock +from rclpy.time import Duration, Time +from rosbridge_library.internal import ros_loader +from rosbridge_library.util import bson + +try: + import rospy +except ImportError: + rospy = None + +type_map = { + "bool": ["bool", "boolean"], + "int": [ + "int8", + "octet", + "uint8", + "char", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + ], + "float": ["float32", "float64", "double", "float"], + "str": ["string"], +} +primitive_types = [bool, int, float] + +list_types = [list, tuple, np.ndarray, array.array] +ros_time_types = ["builtin_interfaces/Time", "builtin_interfaces/Duration"] +ros_primitive_types = [ + "bool", + "boolean", + "octet", + "char", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + "float", + "double", + "string", +] +ros_header_types = ["Header", "std_msgs/Header", "roslib/Header"] +ros_binary_types = ["uint8[]", "char[]", "sequence", "sequence"] +list_tokens = re.compile("<(.+?)>") +bounded_array_tokens = re.compile(r"(.+)\[.*\]") +ros_binary_types_list_braces = [ + ("uint8[]", re.compile(r"uint8\[[^\]]*\]")), + ("char[]", re.compile(r"char\[[^\]]*\]")), +] + +binary_encoder = None +binary_encoder_type = "default" +bson_only_mode = False + + +# TODO(@jubeira): configure module with a node handle. +# The original code doesn't seem to actually use these parameters. +def configure(node_handle=None): + global binary_encoder, binary_encoder_type, bson_only_mode + + if node_handle is not None: + binary_encoder_type = node_handle.get_parameter_or( + "binary_encoder", Parameter("", value="default") + ).value + bson_only_mode = node_handle.get_parameter_or( + "bson_only_mode", Parameter("", value=False) + ).value + + if binary_encoder is None: + if binary_encoder_type == "bson" or bson_only_mode: + binary_encoder = bson.Binary + elif binary_encoder_type == "default" or binary_encoder_type == "b64": + binary_encoder = standard_b64encode + else: + print("Unknown encoder type '%s'" % binary_encoder_type) + exit(0) + + +def get_encoder(): + configure() + return binary_encoder + + +class InvalidMessageException(Exception): + def __init__(self, inst): + Exception.__init__( + self, + "Unable to extract message values from %s instance" % type(inst).__name__, + ) + + +class NonexistentFieldException(Exception): + def __init__(self, basetype, fields): + Exception.__init__( + self, + "Message type {} does not have a field {}".format(basetype, ".".join(fields)), + ) + + +class FieldTypeMismatchException(Exception): + def __init__(self, roottype, fields, expected_type, found_type): + if roottype == expected_type: + Exception.__init__( + self, + f"Expected a JSON object for type {roottype} but received a {found_type}", + ) + else: + Exception.__init__( + self, + "{} message requires a {} for field {}, but got a {}".format( + roottype, expected_type, ".".join(fields), found_type + ), + ) + + +def extract_values(inst): + rostype = msg_instance_type_repr(inst) + if rostype is None: + raise InvalidMessageException(inst=inst) + return _from_inst(inst, rostype) + + +def populate_instance(msg, inst): + """Returns an instance of the provided class, with its fields populated + according to the values in msg""" + inst_type = msg_instance_type_repr(inst) + + return _to_inst(msg, inst_type, inst_type, inst) + + +def msg_instance_type_repr(msg_inst): + """Returns a string representation of a ROS2 message type from a message instance""" + # Message representation: '{package}.msg.{message_name}({fields})'. + # A representation like '_type' member in ROS1 messages is needed: '{package}/{message_name}'. + # E.g: 'std_msgs/Header' + msg_type = type(msg_inst) + if msg_type in primitive_types or msg_type in list_types: + return str(type(msg_inst)) + inst_repr = str(msg_inst).split(".") + return "{}/{}".format(inst_repr[0], inst_repr[2].split("(")[0]) + + +def msg_class_type_repr(msg_class): + """Returns a string representation of a ROS2 message type from a class representation.""" + # The string representation of the class is + # (e.g. ). + # This has to be converted to {package}/msg/{Message} (e.g. std_msgs/msg/String). + class_repr = str(msg_class).split("'")[1].split(".") + return f"{class_repr[0]}/{class_repr[1]}/{class_repr[3]}" + + +def _from_inst(inst, rostype): + global bson_only_mode + # Special case for uint8[], we encode the string + for binary_type, expression in ros_binary_types_list_braces: + if expression.sub(binary_type, rostype) in ros_binary_types: + encoded = get_encoder()(inst) + return encoded.decode("ascii") + + # Check for time or duration + if rostype in ros_time_types: + return {"sec": inst.sec, "nanosec": inst.nanosec} + + if bson_only_mode is None: + bson_only_mode = rospy.get_param("~bson_only_mode", False) + # Check for primitive types + if rostype in ros_primitive_types: + # JSON does not support Inf and NaN. They are mapped to None and encoded as null + if (not bson_only_mode) and (rostype in type_map.get("float")): + if math.isnan(inst) or math.isinf(inst): + return None + + # JSON does not support byte array. They are converted to int + if (not bson_only_mode) and (rostype == "octet"): + return int.from_bytes(inst, "little") + + return inst + + # Check if it's a list or tuple + if type(inst) in list_types: + return _from_list_inst(inst, rostype) + + # Assume it's otherwise a full ros msg object + return _from_object_inst(inst, rostype) + + +def _from_list_inst(inst, rostype): + # Can duck out early if the list is empty + if len(inst) == 0: + return [] + + # Remove the list indicators from the rostype + try: + rostype = re.search(list_tokens, rostype).group(1) + except AttributeError: + rostype = re.search(bounded_array_tokens, rostype).group(1) + + # Shortcut for primitives + if rostype in ros_primitive_types: + # Convert to Built-in integer types to dump as JSON + if isinstance(inst, np.ndarray) and ( + rostype in type_map.get("int") or rostype in type_map.get("float") + ): + return inst.tolist() + + if rostype not in type_map.get("float"): + return list(inst) + + # Call to _to_inst for every element of the list + return [_from_inst(x, rostype) for x in inst] + + +def _from_object_inst(inst, rostype): + # Create an empty dict then populate with values from the inst + msg = {} + # Equivalent for zip(inst.__slots__, inst._slot_types) in ROS1: + for field_name, field_rostype in inst.get_fields_and_field_types().items(): + field_inst = getattr(inst, field_name) + msg[field_name] = _from_inst(field_inst, field_rostype) + return msg + + +def _to_inst(msg, rostype, roottype, inst=None, stack=[]): + # Check if it's uint8[], and if it's a string, try to b64decode + for binary_type, expression in ros_binary_types_list_braces: + if expression.sub(binary_type, rostype) in ros_binary_types: + return _to_binary_inst(msg) + + # Check the type for time or rostime + if rostype in ros_time_types: + return _to_time_inst(msg, rostype, inst) + + # Check to see whether this is a primitive type + if rostype in ros_primitive_types: + return _to_primitive_inst(msg, rostype, roottype, stack) + + # Check whether we're dealing with a list type + if inst is not None and type(inst) in list_types: + return _to_list_inst(msg, rostype, roottype, inst, stack) + + # Otherwise, the type has to be a full ros msg type, so msg must be a dict + if inst is None: + inst = ros_loader.get_message_instance(rostype) + + return _to_object_inst(msg, rostype, roottype, inst, stack) + + +def _to_binary_inst(msg): + if isinstance(msg, str): + return list(standard_b64decode(msg)) + if isinstance(msg, list): + return msg + if isinstance(msg, bytes): + # Using the frombytes() method with a memoryview of the data allows for zero copying of data thanks to Python's buffer protocol (HUGE time-saver for large arrays) + data = array.array("B") + data.frombytes(memoryview(msg)) + return data + return bytes(bytearray(msg)) + + +def _to_time_inst(msg, rostype, inst=None): + # Create an instance if we haven't been provided with one + + if rostype == "builtin_interfaces/Time" and msg == "now": + return ROSClock().now().to_msg() + + if inst is None: + if rostype == "builtin_interfaces/Time": + inst = Time().to_msg() + elif rostype == "builtin_interfaces/Duration": + inst = Duration().to_msg() + else: + return None + + # Copy across the fields, try ROS1 and ROS2 fieldnames + for field in ["sec", "secs"]: + if field in msg: + setattr(inst, "sec", msg[field]) + break + for field in ["nanosec", "nsecs"]: + if field in msg: + setattr(inst, "nanosec", msg[field]) + break + + return inst + + +def _to_primitive_inst(msg, rostype, roottype, stack): + # Typecheck the msg + if isinstance(msg, int) and rostype in type_map["float"]: + # probably wrong parsing, + # fix that by casting the int to the expected float + msg = float(msg) + + # Convert to byte + if rostype == "octet" and isinstance(msg, int): + return bytes([msg]) + + msgtype = type(msg) + if msgtype in primitive_types and rostype in type_map[msgtype.__name__]: + return msg + elif isinstance(msg, str) and rostype in type_map[msgtype.__name__]: + return msg + raise FieldTypeMismatchException(roottype, stack, rostype, msgtype) + + +def _to_list_inst(msg, rostype, roottype, inst, stack): + # Typecheck the msg + if type(msg) not in list_types: + raise FieldTypeMismatchException(roottype, stack, rostype, type(msg)) + + # Can duck out early if the list is empty + if len(msg) == 0: + return [] + + # Special mappings for numeric types https://design.ros2.org/articles/idl_interface_definition.html + if isinstance(inst, array.array): + del inst[:] + inst.extend(msg) # accepts both ints and floats which may come from json + return inst + if isinstance(inst, np.ndarray): + inst[:] = msg # accepts both ints and floats which may come from json + return inst + + # Remove the list indicators from the rostype + try: + rostype = re.search(list_tokens, rostype).group(1) + except AttributeError: + rostype = re.search(bounded_array_tokens, rostype).group(1) + + # Call to _to_inst for every element of the list + return [_to_inst(x, rostype, roottype, None, stack) for x in msg] + + +def _to_object_inst(msg, rostype, roottype, inst, stack): + + # Typecheck the msg + if not isinstance(msg, dict): + raise FieldTypeMismatchException(roottype, stack, rostype, type(msg)) + + # Substitute the correct time if we're an std_msgs/Header + if rostype in ros_header_types: + inst.stamp = ROSClock().now().to_msg() + + inst_fields = inst.get_fields_and_field_types() + + for field_name in msg: + # Add this field to the field stack + field_stack = stack + [field_name] + + # Raise an exception if the msg contains a bad field + if field_name not in inst_fields: + raise NonexistentFieldException(roottype, field_stack) + + field_rostype = inst_fields[field_name] + field_inst = getattr(inst, field_name) + + field_value = _to_inst(msg[field_name], field_rostype, roottype, field_inst, field_stack) + + setattr(inst, field_name, field_value) + + return inst diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py new file mode 100644 index 000000000..c9d7dbc5d --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/outgoing_message.py @@ -0,0 +1,47 @@ +from rosbridge_library.internal.cbor_conversion import extract_cbor_values +from rosbridge_library.internal.message_conversion import ( + extract_values as extract_json_values, +) + +try: + from cbor import dumps as encode_cbor +except ImportError: + from rosbridge_library.util.cbor import dumps as encode_cbor + + +class OutgoingMessage: + """A message wrapper for caching encoding operations.""" + + def __init__(self, message): + self._message = message + self._json_values = None + self._cbor_values = None + self._cbor_msg = None + self._cbor_raw_msg = None + + @property + def message(self): + return self._message + + def get_json_values(self): + if self._json_values is None: + self._json_values = extract_json_values(self._message) + return self._json_values + + def get_cbor_values(self): + if self._cbor_values is None: + self._cbor_values = extract_cbor_values(self._message) + return self._cbor_values + + def get_cbor(self, outgoing_msg): + if self._cbor_msg is None: + outgoing_msg["msg"] = self.get_cbor_values() + self._cbor_msg = encode_cbor(outgoing_msg) + + return self._cbor_msg + + def get_cbor_raw(self, outgoing_msg): + if self._cbor_raw_msg is None: + self._cbor_raw_msg = encode_cbor(outgoing_msg) + + return self._cbor_raw_msg diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/pngcompression.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/pngcompression.py new file mode 100644 index 000000000..a705fdd8e --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/pngcompression.py @@ -0,0 +1,61 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from base64 import standard_b64decode, standard_b64encode +from io import StringIO +from math import ceil, floor, sqrt + +from PIL import Image + + +def encode(string): + """PNG-compress the string in a square RBG image padded with '\n', return the b64 encoded bytes""" + length = len(string) + width = floor(sqrt(length / 3.0)) + height = ceil((length / 3.0) / width) + bytes_needed = int(width * height * 3) + while length < bytes_needed: + string += "\n" + length += 1 + i = Image.frombytes("RGB", (int(width), int(height)), string) + buff = StringIO() + i.save(buff, "png") + encoded = standard_b64encode(buff.getvalue()) + return encoded + + +def decode(string): + """b64 decode the string, then PNG-decompress""" + decoded = standard_b64decode(string) + buff = StringIO(decoded) + i = Image.open(buff) + return i.tostring() diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/publishers.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/publishers.py new file mode 100644 index 000000000..e4f674b70 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/publishers.py @@ -0,0 +1,319 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# Copyright (c) 2014, Creativa 77 SRL +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from threading import Timer + +from rclpy.duration import Duration +from rclpy.qos import DurabilityPolicy, QoSProfile +from rosbridge_library.internal import message_conversion, ros_loader +from rosbridge_library.internal.message_conversion import msg_class_type_repr +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) + + +class MultiPublisher: + """Keeps track of the clients that are using a particular publisher. + + Provides an API to publish messages and register clients that are using + this publisher""" + + def __init__(self, topic, node_handle, msg_type=None, latched_client_id=None, queue_size=100): + """Register a publisher on the specified topic. + + Keyword arguments: + topic -- the name of the topic to register the publisher to + node_handle -- Handle to a rclpy node to create the publisher. + msg_type -- (optional) the type to register the publisher as. If not + provided, an attempt will be made to infer the topic type + latch -- (optional) if a client requested this publisher to be latched, + provide the client_id of that client here + + Throws: + TopicNotEstablishedException -- if no msg_type was specified by the + caller and the topic is not yet established, so a topic type cannot + be inferred + TypeConflictException -- if the msg_type was specified by the + caller and the topic is established, and the established type is + different to the user-specified msg_type + + """ + # First check to see if the topic is already established + topics_names_and_types = dict(node_handle.get_topic_names_and_types()) + topic_type = topics_names_and_types.get(topic) + + # If it's not established and no type was specified, exception + if msg_type is None and topic_type is None: + raise TopicNotEstablishedException(topic) + + # topic_type is a list of types or None at this point; only one type is supported. + if topic_type is not None: + if len(topic_type) > 1: + node_handle.get_logger().warning(f"More than one topic type detected: {topic_type}") + topic_type = topic_type[0] + + # Use the established topic type if none was specified + if msg_type is None: + msg_type = topic_type + + # Load the message class, propagating any exceptions from bad msg types + msg_class = ros_loader.get_message_class(msg_type) + + # Make sure the specified msg type and established msg type are same + msg_type_string = msg_class_type_repr(msg_class) + if topic_type is not None and topic_type != msg_type_string: + raise TypeConflictException(topic, topic_type, msg_type_string) + + # Create the publisher and associated member variables + self.clients = {} + self.latched_client_id = latched_client_id + self.topic = topic + self.node_handle = node_handle + self.msg_class = msg_class + # Adding a lifespan solves the problem of late-joining subscribers + # without the need of a custom message publisher implementation. + publisher_qos = QoSProfile( + depth=queue_size, + durability=DurabilityPolicy.TRANSIENT_LOCAL, + ) + + # For latched clients, no lifespan has to be specified (i.e. latch forever). + # Otherwise we want to keep the messages for a second to prevent late-joining subscribers from + # missing messages. + if latched_client_id is None: + publisher_qos.lifespan = Duration(seconds=1) + else: + publisher_qos.depth = 1 + + self.publisher = node_handle.create_publisher(msg_class, topic, qos_profile=publisher_qos) + + def unregister(self): + """Unregisters the publisher and clears the clients""" + self.node_handle.destroy_publisher(self.publisher) + self.clients.clear() + + def verify_type(self, msg_type): + """Verify that the publisher publishes messages of the specified type. + + Keyword arguments: + msg_type -- the type to check this publisher against + + Throws: + Exception -- if ros_loader cannot load the specified msg type + TypeConflictException -- if the msg_type is different than the type of + this publisher + + """ + if not ros_loader.get_message_class(msg_type) is self.msg_class: + raise TypeConflictException(self.topic, msg_class_type_repr(self.msg_class), msg_type) + return + + def publish(self, msg): + """Publish a message using this publisher. + + Keyword arguments: + msg -- the dict (json) message to publish + + Throws: + Exception -- propagates exceptions from message conversion if the + provided msg does not properly conform to the message type of this + publisher + + """ + # Create a message instance + inst = self.msg_class() + + # Populate the instance, propagating any exceptions that may be thrown + message_conversion.populate_instance(msg, inst) + + # Publish the message + self.publisher.publish(inst) + + def register_client(self, client_id): + """Register the specified client as a client of this publisher. + + Keyword arguments: + client_id -- the ID of the client using the publisher + + """ + self.clients[client_id] = True + + def unregister_client(self, client_id): + """Unregister the specified client from this publisher. + + If the specified client_id is not a client of this publisher, nothing + happens. + + Keyword arguments: + client_id -- the ID of the client to remove + + """ + if client_id in self.clients: + del self.clients[client_id] + + def has_clients(self): + """Return true if there are clients to this publisher.""" + return len(self.clients) != 0 + + +class PublisherManager: + """The PublisherManager keeps track of ROS publishers + + It maintains a MultiPublisher instance for each registered topic + + When unregistering a client, if there are no more clients for a publisher, + then that publisher is unregistered from the ROS Master + """ + + def __init__(self): + self._publishers = {} + self.unregister_timers = {} + self.unregister_timeout = 10.0 + + def register(self, client_id, topic, node_handle, msg_type=None, latch=False, queue_size=100): + """Register a publisher on the specified topic. + + Publishers are shared between clients, so a single MultiPublisher + instance is created per topic, even if multiple clients register. + + Keyword arguments: + client_id -- the ID of the client making this request + topic -- the name of the topic to publish on + node_handle -- Handle to a rclpy node to create the publisher. + msg_type -- (optional) the type to publish + latch -- (optional) whether to make this publisher latched + queue_size -- (optional) rospy publisher queue_size to use + + Throws: + Exception -- exceptions are propagated from the MultiPublisher if + there is a problem loading the specified msg class or establishing + the publisher + + """ + latched_client_id = client_id if latch else None + if topic not in self._publishers: + self._publishers[topic] = MultiPublisher( + topic, + node_handle, + msg_type=msg_type, + latched_client_id=latched_client_id, + queue_size=queue_size, + ) + elif latch and self._publishers[topic].latched_client_id != client_id: + node_handle.get_logger().warn( + f"Client ID {client_id} attempted to register topic [{topic}] as " + "latched but this topic was previously registered." + ) + node_handle.get_logger().warn( + "Only a single registered latched publisher is supported at the time" + ) + elif not latch and self._publishers[topic].latched_client_id: + node_handle.get_logger().warn( + f"New non-latched publisher registration for topic [{topic}] which is " + "already registered as latched. but this topic was previously registered." + ) + node_handle.get_logger().warn( + "Only a single registered latched publisher is supported at the time" + ) + + if msg_type is not None: + self._publishers[topic].verify_type(msg_type) + + self._publishers[topic].register_client(client_id) + + def unregister(self, client_id, topic): + """Unregister a client from the publisher for the given topic. + Will wait some time before actually unregistering, it is done in + _unregister_impl + + If there are no clients remaining for that publisher, then the + publisher is unregistered from the ROS Master + + Keyword arguments: + client_id -- the ID of the client making this request + topic -- the topic to unregister the publisher for + + """ + if topic not in self._publishers: + return + + self._publishers[topic].unregister_client(client_id) + if topic in self.unregister_timers: + self.unregister_timers[topic].cancel() + del self.unregister_timers[topic] + self.unregister_timers[topic] = Timer( + self.unregister_timeout, self._unregister_impl, [topic] + ) + self.unregister_timers[topic].start() + + def _unregister_impl(self, topic): + if not self._publishers[topic].has_clients(): + self._publishers[topic].unregister() + del self._publishers[topic] + del self.unregister_timers[topic] + + def unregister_all(self, client_id): + """Unregisters a client from all publishers that they are registered + to. + + Keyword arguments: + client_id -- the ID of the client making this request""" + for topic in self._publishers.keys(): + self.unregister(client_id, topic) + + def publish(self, client_id, topic, msg, node_handle, latch=False, queue_size=100): + """Publish a message on the given topic. + + Tries to create a publisher on the topic if one does not already exist. + + Keyword arguments: + client_id -- the ID of the client making this request + topic -- the topic to publish the message on + msg -- a JSON-like dict of fields and values + node_handle -- Handle to a rclpy node to create the publisher. + latch -- (optional) whether to make this publisher latched + queue_size -- (optional) rospy publisher queue_size to use + + Throws: + Exception -- a variety of exceptions are propagated. They can be + thrown if there is a problem setting up or getting the publisher, + or if the provided msg does not map to the msg class of the publisher. + + """ + self.register(client_id, topic, node_handle, latch=latch, queue_size=queue_size) + + self._publishers[topic].publish(msg) + + +manager = PublisherManager() diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/ros_loader.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/ros_loader.py new file mode 100644 index 000000000..3780d45a7 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/ros_loader.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import importlib +from threading import Lock + +""" ros_loader contains methods for dynamically loading ROS message classes at +runtime. It's achieved by using roslib to load the manifest files for the +package that the respective class is contained in. + +Methods typically return the requested class or instance, or None if not found +""" + +# Variable containing the loaded classes +_loaded_msgs = {} +_loaded_srvs = {} +_msgs_lock = Lock() +_srvs_lock = Lock() + + +class InvalidTypeStringException(Exception): + def __init__(self, typestring): + Exception.__init__(self, "%s is not a valid type string" % typestring) + + +class InvalidModuleException(Exception): + def __init__(self, modname, subname, original_exception): + Exception.__init__( + self, + "Unable to import %s.%s from package %s. Caused by: %s" + % (modname, subname, modname, str(original_exception)), + ) + + +class InvalidClassException(Exception): + def __init__(self, modname, subname, classname, original_exception): + Exception.__init__( + self, + "Unable to import %s class %s from package %s. Caused by %s" + % (subname, classname, modname, str(original_exception)), + ) + + +def get_message_class(typestring): + """Loads the message type specified. + + Returns the loaded class, or throws exceptions on failure""" + return _get_msg_class(typestring) + + +def get_service_class(typestring): + """Loads the service type specified. + + Returns the loaded class, or None on failure""" + return _get_srv_class(typestring) + + +def get_message_instance(typestring): + """If not loaded, loads the specified type. + Then returns an instance of it, or None.""" + cls = get_message_class(typestring) + return cls() + + +def get_service_request_instance(typestring): + cls = get_service_class(typestring) + return cls.Request() + + +def get_service_response_instance(typestring): + cls = get_service_class(typestring) + return cls.Response() + + +def _get_msg_class(typestring): + """If not loaded, loads the specified msg class then returns an instance + of it + + Throws various exceptions if loading the msg class fails""" + global _loaded_msgs, _msgs_lock + try: + # The type string starts with the package and ends with the + # class and contains module subnames in between. For + # compatibility with ROS1 style types, we fall back to use a + # standard "msg" subname. + splits = [x for x in typestring.split("/") if x] + if len(splits) > 2: + subname = ".".join(splits[1:-1]) + else: + subname = "msg" + + return _get_class(typestring, subname, _loaded_msgs, _msgs_lock) + except (InvalidModuleException, InvalidClassException): + return _get_class(typestring, "msg", _loaded_msgs, _msgs_lock) + + +def _get_srv_class(typestring): + """If not loaded, loads the specified srv class then returns an instance + of it + + Throws various exceptions if loading the srv class fails""" + global _loaded_srvs, _srvs_lock + try: + # The type string starts with the package and ends with the + # class and contains module subnames in between. For + # compatibility with ROS1 style types, we fall back to use a + # standard "srv" subname. + splits = [x for x in typestring.split("/") if x] + if len(splits) > 2: + subname = ".".join(splits[1:-1]) + else: + subname = "srv" + + return _get_class(typestring, subname, _loaded_srvs, _srvs_lock) + except (InvalidModuleException, InvalidClassException): + return _get_class(typestring, "srv", _loaded_srvs, _srvs_lock) + + +def _get_class(typestring, subname, cache, lock): + """If not loaded, loads the specified class then returns an instance + of it. + + Loaded classes are cached in the provided cache dict + + Throws various exceptions if loading the msg class fails""" + + # First, see if we have this type string cached + cls = _get_from_cache(cache, lock, typestring) + if cls is not None: + return cls + + # Now normalise the typestring + modname, classname = _splittype(typestring) + norm_typestring = modname + "/" + classname + + # Check to see if the normalised type string is cached + cls = _get_from_cache(cache, lock, norm_typestring) + if cls is not None: + return cls + + # Load the class + cls = _load_class(modname, subname, classname) + + # Cache the class for both the regular and normalised typestring + _add_to_cache(cache, lock, typestring, cls) + _add_to_cache(cache, lock, norm_typestring, cls) + + return cls + + +def _load_class(modname, subname, classname): + """Loads the manifest and imports the module that contains the specified + type. + + Logic is similar to that of roslib.message.get_message_class, but we want + more expressive exceptions. + + Returns the loaded module, or None on failure""" + + # This assumes the module is already in the path. + try: + pypkg = importlib.import_module(f"{modname}.{subname}") + except Exception as exc: + raise InvalidModuleException(modname, subname, exc) + + try: + return getattr(pypkg, classname) + except Exception as exc: + raise InvalidClassException(modname, subname, classname, exc) + + +def _splittype(typestring): + """Split the string the / delimiter and strip out empty strings + + Performs similar logic to roslib.names.package_resource_name but is a bit + more forgiving about excess slashes + """ + splits = [x for x in typestring.split("/") if x] + if len(splits) == 3: + return (splits[0], splits[2]) + if len(splits) == 2: + return (splits[0], splits[1]) + raise InvalidTypeStringException(typestring) + + +def _add_to_cache(cache, lock, key, value): + lock.acquire() + cache[key] = value + lock.release() + + +def _get_from_cache(cache, lock, key): + """Returns the value for the specified key from the cache. + Locks the lock before doing anything. Returns None if key not in cache""" + lock.acquire() + ret = None + if key in cache: + ret = cache[key] + lock.release() + return ret diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/services.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/services.py new file mode 100644 index 000000000..fc9a89637 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/services.py @@ -0,0 +1,134 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from threading import Thread + +from rclpy.expand_topic_name import expand_topic_name +from rosbridge_library.internal.message_conversion import ( + extract_values, + populate_instance, +) +from rosbridge_library.internal.ros_loader import ( + get_service_class, + get_service_request_instance, +) + + +class InvalidServiceException(Exception): + def __init__(self, servicename): + Exception.__init__(self, "Service %s does not exist" % servicename) + + +class ServiceCaller(Thread): + def __init__(self, service, args, success_callback, error_callback, node_handle): + """Create a service caller for the specified service. Use start() + to start in a separate thread or run() to run in this thread. + + Keyword arguments: + service -- the name of the service to call + args -- arguments to pass to the service. Can be an + ordered list, or a dict of name-value pairs. Anything else will be + treated as though no arguments were provided (which is still valid for + some kinds of service) + success_callback -- a callback to call with the JSON result of the + service call + error_callback -- a callback to call if an error occurs. The + callback will be passed the exception that caused the failure + node_handle -- a ROS2 node handle to call services. + """ + Thread.__init__(self) + self.daemon = True + self.service = service + self.args = args + self.success = success_callback + self.error = error_callback + self.node_handle = node_handle + + def run(self): + try: + # Call the service and pass the result to the success handler + self.success(call_service(self.node_handle, self.service, self.args)) + except Exception as e: + # On error, just pass the exception to the error handler + self.error(e) + + +def args_to_service_request_instance(service, inst, args): + """Populate a service request instance with the provided args + + args can be a dictionary of values, or a list, or None + + Propagates any exceptions that may be raised.""" + msg = {} + if isinstance(args, list): + msg = dict(zip(inst.get_fields_and_field_types().keys(), args)) + elif isinstance(args, dict): + msg = args + + # Populate the provided instance, propagating any exceptions + populate_instance(msg, inst) + + +def call_service(node_handle, service, args=None): + # Given the service name, fetch the type and class of the service, + # and a request instance + + # This should be equivalent to rospy.resolve_name. + service = expand_topic_name(service, node_handle.get_name(), node_handle.get_namespace()) + + service_names_and_types = dict(node_handle.get_service_names_and_types()) + service_type = service_names_and_types.get(service) + if service_type is None: + raise InvalidServiceException(service) + # service_type is a tuple of types at this point; only one type is supported. + if len(service_type) > 1: + node_handle.get_logger().warning(f"More than one service type detected: {service_type}") + service_type = service_type[0] + + service_class = get_service_class(service_type) + inst = get_service_request_instance(service_type) + + # Populate the instance with the provided args + args_to_service_request_instance(service, inst, args) + + client = node_handle.create_client(service_class, service) + + result = client.call(inst) + + node_handle.destroy_client(client) + if result is not None: + # Turn the response into JSON and pass to the callback + json_response = extract_values(result) + else: + raise Exception(result) + + return json_response diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/subscribers.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/subscribers.py new file mode 100644 index 000000000..0bb94a809 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/subscribers.py @@ -0,0 +1,300 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# Copyright (c) 2013, PAL Robotics SL +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from threading import Lock, RLock + +from rclpy.callback_groups import MutuallyExclusiveCallbackGroup +from rclpy.qos import DurabilityPolicy, QoSProfile, ReliabilityPolicy +from rosbridge_library.internal import ros_loader +from rosbridge_library.internal.message_conversion import msg_class_type_repr +from rosbridge_library.internal.outgoing_message import OutgoingMessage +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) + +""" Manages and interfaces with ROS Subscriber objects. A single subscriber +is shared between multiple clients +""" + + +class MultiSubscriber: + """Handles multiple clients for a single subscriber. + + Converts msgs to JSON before handing them to callbacks. Due to subscriber + callbacks being called in separate threads, must lock whenever modifying + or accessing the subscribed clients.""" + + def __init__(self, topic, client_id, callback, node_handle, msg_type=None, raw=False): + """Register a subscriber on the specified topic. + + Keyword arguments: + topic -- the name of the topic to register the subscriber on + client_id -- the ID of the client subscribing + callback -- this client's callback, that will be called for incoming + messages + node_handle -- Handle to a rclpy node to create the publisher. + msg_type -- (optional) the type to register the subscriber as. If not + provided, an attempt will be made to infer the topic type + + Throws: + TopicNotEstablishedException -- if no msg_type was specified by the + caller and the topic is not yet established, so a topic type cannot + be inferred + TypeConflictException -- if the msg_type was specified by the + caller and the topic is established, and the established type is + different to the user-specified msg_type + + """ + # First check to see if the topic is already established + topics_names_and_types = dict(node_handle.get_topic_names_and_types()) + topic_type = topics_names_and_types.get(topic) + + # If it's not established and no type was specified, exception + if msg_type is None and topic_type is None: + raise TopicNotEstablishedException(topic) + + # topic_type is a list of types or None at this point; only one type is supported. + if topic_type is not None: + if len(topic_type) > 1: + node_handle.get_logger().warning(f"More than one topic type detected: {topic_type}") + topic_type = topic_type[0] + + # Use the established topic type if none was specified + if msg_type is None: + msg_type = topic_type + + # Load the message class, propagating any exceptions from bad msg types + msg_class = ros_loader.get_message_class(msg_type) + + # Make sure the specified msg type and established msg type are same + msg_type_string = msg_class_type_repr(msg_class) + if topic_type is not None and topic_type != msg_type_string: + raise TypeConflictException(topic, topic_type, msg_type_string) + + # Certain combinations of publisher and subscriber QoS parameters are + # incompatible. Here we make a "best effort" attempt to match existing + # publishers for the requested topic. This is not perfect because more + # publishers may come online after our subscriber is set up, but we try + # to provide sane defaults. For more information, see: + # - https://docs.ros.org/en/rolling/Concepts/About-Quality-of-Service-Settings.html + # - https://github.com/RobotWebTools/rosbridge_suite/issues/551 + qos = QoSProfile( + depth=10, + durability=DurabilityPolicy.VOLATILE, + reliability=ReliabilityPolicy.RELIABLE, + ) + + infos = node_handle.get_publishers_info_by_topic(topic) + if any(pub.qos_profile.durability == DurabilityPolicy.TRANSIENT_LOCAL for pub in infos): + qos.durability = DurabilityPolicy.TRANSIENT_LOCAL + if any(pub.qos_profile.reliability == ReliabilityPolicy.BEST_EFFORT for pub in infos): + qos.reliability = ReliabilityPolicy.BEST_EFFORT + + # Create the subscriber and associated member variables + # Subscriptions is initialized with the current client to start with. + self.subscriptions = {client_id: callback} + self.rlock = RLock() + self.msg_class = msg_class + self.node_handle = node_handle + self.topic = topic + self.qos = qos + self.raw = raw + self.callback_group = MutuallyExclusiveCallbackGroup() + + self.subscriber = node_handle.create_subscription( + msg_class, topic, self.callback, qos, raw=raw, callback_group=self.callback_group + ) + self.new_subscriber = None + self.new_subscriptions = {} + + def unregister(self): + self.node_handle.destroy_subscription(self.subscriber) + with self.rlock: + self.subscriptions.clear() + if self.new_subscriber: + self.node_handle.destroy_subscription(self.new_subscriber) + self.new_subscriber = None + + def verify_type(self, msg_type): + """Verify that the subscriber subscribes to messages of this type. + + Keyword arguments: + msg_type -- the type to check this subscriber against + + Throws: + Exception -- if ros_loader cannot load the specified msg type + TypeConflictException -- if the msg_type is different than the type of + this publisher + + """ + if not ros_loader.get_message_class(msg_type) is self.msg_class: + raise TypeConflictException(self.topic, msg_class_type_repr(self.msg_class), msg_type) + + def subscribe(self, client_id, callback): + """Subscribe the specified client to this subscriber. + + Keyword arguments: + client_id -- the ID of the client subscribing + callback -- this client's callback, that will be called for incoming + messages + + """ + with self.rlock: + # If the topic is latched, adding a new subscriber will immediately invoke + # the given callback. + # In any case, the first message is handled using new_sub_callback, + # which adds the new callback to the subscriptions dictionary. + self.new_subscriptions.update({client_id: callback}) + if self.new_subscriber is None: + self.new_subscriber = self.node_handle.create_subscription( + self.msg_class, + self.topic, + self._new_sub_callback, + self.qos, + raw=self.raw, + callback_group=self.callback_group, + ) + + def unsubscribe(self, client_id): + """Unsubscribe the specified client from this subscriber + + Keyword arguments: + client_id -- the ID of the client to unsubscribe + + """ + with self.rlock: + if client_id in self.new_subscriptions: + del self.new_subscriptions[client_id] + else: + del self.subscriptions[client_id] + + def has_subscribers(self): + """Return true if there are subscribers""" + with self.rlock: + return len(self.subscriptions) + len(self.new_subscriptions) != 0 + + def callback(self, msg, callbacks=None): + """Callback for incoming messages on the rclpy subscription. + + Passes the message to registered subscriber callbacks. + + Keyword Arguments: + msg - the ROS message coming from the subscriber + callbacks - subscriber callbacks to invoke + + """ + outgoing = OutgoingMessage(msg) + + with self.rlock: + callbacks = callbacks or self.subscriptions.values() + + # Pass the JSON to each of the callbacks + for callback in callbacks: + try: + callback(outgoing) + except Exception as exc: + # Do nothing if one particular callback fails except log it + self.node_handle.get_logger().error( + f"Exception calling subscribe callback: {exc}" + ) + + def _new_sub_callback(self, msg): + """ + Callbacks for new subscribers. + + If the topic was latched, a new subscriber has to be added to receive + a new message and route it to the new subscriptor. + + After the first message is routed, the new subscriber is deleted and + the subscriptions dictionary is updated with the newly incorporated + subscriptors. + """ + with self.rlock: + self.callback(msg, self.new_subscriptions.values()) + self.subscriptions.update(self.new_subscriptions) + self.new_subscriptions = {} + self.node_handle.destroy_subscription(self.new_subscriber) + self.new_subscriber = None + + +class SubscriberManager: + """ + Keeps track of client subscriptions + """ + + def __init__(self): + self._lock = Lock() + self._subscribers = {} + + def subscribe(self, client_id, topic, callback, node_handle, msg_type=None, raw=False): + """Subscribe to a topic + + Keyword arguments: + client_id -- the ID of the client making this subscribe request + topic -- the name of the topic to subscribe to + callback -- the callback to call for incoming messages on the topic + msg_type -- (optional) the type of the topic + + """ + with self._lock: + if topic not in self._subscribers: + self._subscribers[topic] = MultiSubscriber( + topic, client_id, callback, node_handle, msg_type=msg_type, raw=raw + ) + else: + self._subscribers[topic].subscribe(client_id, callback) + + if msg_type is not None and not raw: + self._subscribers[topic].verify_type(msg_type) + + def unsubscribe(self, client_id, topic): + """Unsubscribe from a topic + + Keyword arguments: + client_id -- the ID of the client to unsubscribe + topic -- the topic to unsubscribe from + + """ + with self._lock: + if topic not in self._subscribers: + return + + self._subscribers[topic].unsubscribe(client_id) + + if not self._subscribers[topic].has_subscribers(): + self._subscribers[topic].unregister() + del self._subscribers[topic] + + +manager = SubscriberManager() diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py new file mode 100644 index 000000000..e68faee4a --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/subscription_modifiers.py @@ -0,0 +1,168 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import sys +import traceback +from collections import deque +from threading import Condition, Thread +from time import time + +""" Sits between incoming messages from a subscription, and the outgoing +publish method. Provides throttling / buffering capabilities. + +When the parameters change, the handler may transition to a different kind +of handler +""" + + +class MessageHandler: + def __init__(self, previous_handler=None, publish=None): + if previous_handler: + self.last_publish = previous_handler.last_publish + self.throttle_rate = previous_handler.throttle_rate + self.queue_length = previous_handler.queue_length + self.publish = previous_handler.publish + else: + self.last_publish = 0 + self.throttle_rate = 0 + self.queue_length = 0 + self.publish = publish + + def set_throttle_rate(self, throttle_rate): + self.throttle_rate = throttle_rate / 1000.0 + return self.transition() + + def set_queue_length(self, queue_length): + self.queue_length = queue_length + return self.transition() + + def time_remaining(self): + return max((self.last_publish + self.throttle_rate) - time(), 0) + + def handle_message(self, msg): + self.last_publish = time() + self.publish(msg) + + def transition(self): + if self.throttle_rate == 0 and self.queue_length == 0: + return self + elif self.queue_length == 0: + return ThrottleMessageHandler(self) + else: + return QueueMessageHandler(self) + + def finish(self, block=True): + pass + + +class ThrottleMessageHandler(MessageHandler): + def handle_message(self, msg): + if self.time_remaining() == 0: + MessageHandler.handle_message(self, msg) + + def transition(self): + if self.throttle_rate == 0 and self.queue_length == 0: + return MessageHandler(self) + elif self.queue_length == 0: + return self + else: + return QueueMessageHandler(self) + + def finish(self, block=True): + pass + + +class QueueMessageHandler(MessageHandler, Thread): + def __init__(self, previous_handler): + Thread.__init__(self) + MessageHandler.__init__(self, previous_handler) + self.daemon = True + self.queue = deque(maxlen=self.queue_length) + self.c = Condition() + self.alive = True + self.start() + + def handle_message(self, msg): + with self.c: + if not self.alive: + return + should_notify = len(self.queue) == 0 + self.queue.append(msg) + if should_notify: + self.c.notify() + + def transition(self): + if self.throttle_rate == 0 and self.queue_length == 0: + self.finish() + return MessageHandler(self) + elif self.queue_length == 0: + self.finish() + return ThrottleMessageHandler(self) + else: + with self.c: + old_queue = self.queue + self.queue = deque(maxlen=self.queue_length) + while len(old_queue) > 0: + self.queue.append(old_queue.popleft()) + self.c.notify() + return self + + def finish(self, block=True): + """If throttle was set to 0, this pushes all buffered messages""" + # Notify the thread to finish + with self.c: + self.alive = False + self.c.notify() + + if block: + self.join() + + def run(self): + while self.alive: + msg = None + with self.c: + if len(self.queue) == 0: + self.c.wait() + else: + self.c.wait(self.time_remaining()) + if self.alive and self.time_remaining() == 0 and len(self.queue) > 0: + msg = self.queue.popleft() + if msg is not None: + try: + MessageHandler.handle_message(self, msg) + except Exception: + traceback.print_exc(file=sys.stderr) + while self.time_remaining() == 0 and len(self.queue) > 0: + try: + MessageHandler.handle_message(self, self.queue[0]) + except Exception: + traceback.print_exc(file=sys.stderr) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/topics.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/topics.py new file mode 100644 index 000000000..c47cc0353 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/internal/topics.py @@ -0,0 +1,53 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +""" Exceptions and code common to both publishers and subscribers """ + + +class TopicNotEstablishedException(Exception): + def __init__(self, topic): + Exception.__init__( + self, + "Cannot infer topic type for topic %s as it is not yet advertised" % (topic,), + ) + + +class TypeConflictException(Exception): + def __init__(self, topic, orig_type, new_type): + Exception.__init__( + self, + ( + "Tried to register topic %s with type %s but it is already" + + " established with type %s" + ) + % (topic, new_type, orig_type), + ) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/protocol.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/protocol.py new file mode 100644 index 000000000..8e2cc1aeb --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/protocol.py @@ -0,0 +1,401 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import time + +from rosbridge_library.capabilities.fragmentation import Fragmentation +from rosbridge_library.util import bson, json + + +def is_number(s): + try: + float(s) + return True + except ValueError: + return False + + +def has_binary(obj): + """Returns True if obj is a binary or contains a binary attribute""" + + if isinstance(obj, list): + return any(has_binary(item) for item in obj) + + if isinstance(obj, dict): + return any(has_binary(obj[item]) for item in obj) + + return isinstance(obj, bson.binary.Binary) + + +class Protocol: + """The interface for a single client to interact with ROS. + + See rosbridge_protocol for the default protocol used by rosbridge + + The lifecycle for a Protocol instance is as follows: + - Pass incoming messages from the client to incoming + - Propagate outgoing messages to the client by overriding outgoing + - Call finish to clean up resources when the client is finished + + """ + + # fragment_size can be set per client (each client has its own instance of protocol) + # ..same for other parameters + fragment_size = None + png = None + # buffer used to gather partial JSON-objects (could be caused by small tcp-buffers or similar..) + buffer = "" + old_buffer = "" + busy = False + # if this is too low, ("simple")clients network stacks will get flooded (when sending fragments of a huge message..) + # .. depends on message_size/bandwidth/performance/client_limits/... + # !! this might be related to (or even be avoided by using) throttle_rate !! + delay_between_messages = 0 + # global list of non-ros advertised services + external_service_list = {} + # Use only BSON for the whole communication if the server has been started with bson_only_mode:=True + bson_only_mode = False + + parameters = None + + def __init__(self, client_id, node_handle): + """Keyword arguments: + client_id -- a unique ID for this client to take. Uniqueness is + important otherwise there will be conflicts between multiple clients + with shared resources + node_handle -- a ROS2 node handle. + + """ + self.client_id = client_id + self.capabilities = [] + self.operations = {} + self.node_handle = node_handle + + if self.parameters: + self.fragment_size = self.parameters["max_message_size"] + self.delay_between_messages = self.parameters["delay_between_messages"] + self.bson_only_mode = self.parameters.get("bson_only_mode", False) + + # added default message_string="" to allow recalling incoming until buffer is empty without giving a parameter + # --> allows to get rid of (..or minimize) delay between client-side sends + def incoming(self, message_string=""): + """Process an incoming message from the client + + Keyword arguments: + message_string -- the wire-level message sent by the client + + """ + if len(self.buffer) > 0: + self.buffer = self.buffer + message_string + else: + self.buffer = message_string + msg = None + + # take care of having multiple JSON-objects in receiving buffer + # ..first, try to load the whole buffer as a JSON-object + try: + msg = self.deserialize(self.buffer) + self.buffer = "" + + # if loading whole object fails try to load part of it (from first opening bracket "{" to next closing bracket "}" + # .. this causes Exceptions on "inner" closing brackets --> so I suppressed logging of deserialization errors + except Exception: + if self.bson_only_mode: + # Since BSON should be used in conjunction with a network handler + # that receives exactly one full BSON message. + # This will then be passed to self.deserialize and shouldn't cause any + # exceptions because of fragmented messages (broken or invalid messages might still be sent tough) + self.log("error", "Exception in deserialization of BSON") + + else: + # TODO: handling of partial/multiple/broken json data in incoming buffer + # this way is problematic when json contains nested json-objects ( e.g. { ... { "config": [0,1,2,3] } ... } ) + # .. if outer json is not fully received, stepping through opening brackets will find { "config" : ... } as a valid json object + # .. and pass this "inner" object to rosbridge and throw away the leading part of the "outer" object.. + # solution for now: + # .. check for "op"-field. i can still imagine cases where a nested message ( e.g. complete service_response fits into the data field of a fragment..) + # .. would cause trouble, but if a response fits as a whole into a fragment, simply do not pack it into a fragment. + # + # --> from that follows current limitation: + # fragment data must NOT (!) contain a complete json-object that has an "op-field" + # + # an alternative solution would be to only check from first opening bracket and have a time out on data in input buffer.. (to handle broken data) + opening_brackets = [i for i, letter in enumerate(self.buffer) if letter == "{"] + closing_brackets = [i for i, letter in enumerate(self.buffer) if letter == "}"] + + for start in opening_brackets: + for end in closing_brackets: + try: + msg = self.deserialize(self.buffer[start : end + 1]) + if msg.get("op", None) is not None: + # TODO: check if throwing away leading data like this is okay.. loops look okay.. + self.buffer = self.buffer[end + 1 : len(self.buffer)] + # jump out of inner loop if json-decode succeeded + break + except Exception: + # debug json-decode errors with this line + # print e + pass + # if load was successful --> break outer loop, too.. -> no need to check if json begins at a "later" opening bracket.. + if msg is not None: + break + + # if decoding of buffer failed .. simply return + if msg is None: + return + + # process fields JSON-message object that "control" rosbridge + mid = None + if "id" in msg: + mid = msg["id"] + if "op" not in msg: + if "receiver" in msg: + self.log( + "error", + "Received a rosbridge v1.0 message. Please refer to rosbridge.org for the correct format of rosbridge v2.0 messages. Original message was: %s" + % message_string, + ) + else: + self.log( + "error", + f"Received a message without an op. All messages require 'op' field with value one of: {list(self.operations.keys())}. Original message was: {message_string}", + mid, + ) + return + op = msg["op"] + if op not in self.operations: + self.log( + "error", + f"Unknown operation: {op}. Allowed operations: {list(self.operations.keys())}", + mid, + ) + return + # this way a client can change/overwrite it's active values anytime by just including parameter field in any message sent to rosbridge + # maybe need to be improved to bind parameter values to specific operation.. + if "fragment_size" in msg.keys(): + self.fragment_size = msg["fragment_size"] + # print "fragment size set to:", self.fragment_size + if "message_intervall" in msg.keys() and is_number(msg["message_intervall"]): + self.delay_between_messages = msg["message_intervall"] + if "png" in msg.keys(): + self.png = msg["msg"] + + # now try to pass message to according operation + try: + self.operations[op](msg) + except Exception as exc: + self.log("error", f"{op}: {str(exc)}", mid) + + # if anything left in buffer .. re-call self.incoming + # TODO: check what happens if we have "garbage" on tcp-stack --> infinite loop might be triggered! .. might get out of it when next valid JSON arrives since only data after last 'valid' closing bracket is kept + if len(self.buffer) > 0: + # try to avoid infinite loop.. + if self.old_buffer != self.buffer: + self.old_buffer = self.buffer + self.incoming() + + def outgoing(self, message, compression="none"): + """Pass an outgoing message to the client. This method should be + overridden. + + Keyword arguments: + message -- the wire-level message to send to the client + + """ + pass + + def send(self, message, cid=None, compression="none"): + """Called internally in preparation for sending messages to the client + + This method pre-processes the message then passes it to the overridden + outgoing method. + + Keyword arguments: + message -- a dict of message values to be marshalled and sent + cid -- (optional) an associated id + + """ + serialized = ( + message if compression in ["cbor", "cbor-raw"] else self.serialize(message, cid) + ) + if serialized is not None: + if self.png == "png": + # TODO: png compression on outgoing messages + # encode message + pass + + fragment_list = None + if self.fragment_size is not None and len(serialized) > self.fragment_size: + mid = message.get("id", None) + + # TODO: think about splitting into fragments that have specified size including header-fields! + # --> estimate header size --> split content into fragments that have the requested overall size, rather than requested content size + fragment_list = Fragmentation(self).fragment(message, self.fragment_size, mid) + + # fragment list not empty -> send fragments + if fragment_list is not None: + for fragment in fragment_list: + if self.bson_only_mode: + self.outgoing(bson.BSON.encode(fragment), compression) + else: + self.outgoing(json.dumps(fragment), compression) + # okay to use delay here (sender's send()-function) because rosbridge is sending next request only to service provider when last one had finished) + # --> if this was not the case this delay needed to be implemented in service-provider's (meaning message receiver's) send_message()-function in rosbridge_tcp.py) + time.sleep(self.delay_between_messages) + # else send message as it is + else: + self.outgoing(serialized, compression) + time.sleep(self.delay_between_messages) + + def finish(self): + """Indicate that the client is finished and clean up resources. + + All clients should call this method after disconnecting. + + """ + for capability in self.capabilities: + capability.finish() + + def serialize(self, msg, cid=None): + """Turns a dictionary of values into the appropriate wire-level + representation. + + Default behaviour uses JSON. Override to use a different container. + + Keyword arguments: + msg -- the dictionary of values to serialize + cid -- (optional) an ID associated with this. Will be logged on err. + + Returns a JSON string representing the dictionary + """ + try: + if isinstance(msg, bytearray): + return msg + if has_binary(msg) or self.bson_only_mode: + return bson.BSON.encode(msg) + else: + return json.dumps(msg) + except Exception as e: + self.log("error", f"Unable to serialize message '{msg}': {e}") + return None + + def deserialize(self, msg, cid=None): + + """Turns the wire-level representation into a dictionary of values + + Default behaviour assumes JSON. Override to use a different container. + + Keyword arguments: + msg -- the wire-level message to deserialize + cid -- (optional) an ID associated with this. Is logged on error + + Returns a dictionary of values + + """ + try: + if self.bson_only_mode: + bson_message = bson.BSON(msg) + return bson_message.decode() + else: + return json.loads(msg) + except Exception: + # if we did try to deserialize whole buffer .. first try to let self.incoming check for multiple/partial json-decodes before logging error + # .. this means, if buffer is not == msg --> we tried to decode part of buffer + + # TODO: implement a way to have a final Exception when nothing works out to decode (multiple/broken/partial JSON..) + + # suppressed logging of exception on json-decode to keep rosbridge-logs "clean", otherwise console logs would get spammed for every failed json-decode try + # if msg != self.buffer: + # error_msg = "Unable to deserialize message from client: %s" % msg + # error_msg += "\nException was: " +str(e) + # + # self.log("error", error_msg, cid) + + # re-raise Exception to allow handling outside of deserialize function instead of returning None + raise + # return None + + def register_operation(self, opcode, handler): + """Register a handler for an opcode + + Keyword arguments: + opcode -- the opcode to register this handler for + handler -- a callback function to call for messages with this opcode + + """ + self.operations[opcode] = handler + + def unregister_operation(self, opcode): + """Unregister a handler for an opcode + + Keyword arguments: + opcode -- the opcode to unregister the handler for + + """ + if opcode in self.operations: + del self.operations[opcode] + + def add_capability(self, capability_class): + """Add a capability to the protocol. + + This method is for convenience; assumes the default capability + constructor + + Keyword arguments: + capability_class -- the class of the capability to add + + """ + self.capabilities.append(capability_class(self)) + + def log(self, level, message, lid=None): + """Log a message to the client. By default just sends to stdout + + Keyword arguments: + level -- the logger level of this message + message -- the string message to send to the user + lid -- an associated for this log message + + """ + stdout_formatted_msg = None + if lid is not None: + stdout_formatted_msg = f"[Client {self.client_id}] [id: {lid}] {message}" + else: + stdout_formatted_msg = f"[Client {self.client_id}] {message}" + + if level == "error" or level == "err": + self.node_handle.get_logger().error(stdout_formatted_msg) + elif level == "warning" or level == "warn": + self.node_handle.get_logger().warn(stdout_formatted_msg) + elif level == "info" or level == "information": + self.node_handle.get_logger().info(stdout_formatted_msg) + else: + self.node_handle.get_logger().debug(stdout_formatted_msg) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py new file mode 100644 index 000000000..f8dca1b8b --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/rosbridge_protocol.py @@ -0,0 +1,72 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +from rosbridge_library.capabilities.advertise import Advertise + +# imports for external service_server +from rosbridge_library.capabilities.advertise_service import AdvertiseService +from rosbridge_library.capabilities.call_service import CallService + +# imports for defragmentation +from rosbridge_library.capabilities.defragmentation import Defragment +from rosbridge_library.capabilities.publish import Publish +from rosbridge_library.capabilities.service_response import ServiceResponse +from rosbridge_library.capabilities.subscribe import Subscribe +from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService +from rosbridge_library.protocol import Protocol + + +class RosbridgeProtocol(Protocol): + """Adds the handlers for the rosbridge opcodes""" + + rosbridge_capabilities = [ + CallService, + Advertise, + Publish, + Subscribe, + Defragment, + AdvertiseService, + ServiceResponse, + UnadvertiseService, + ] + + print("registered capabilities (classes):") + for cap in rosbridge_capabilities: + print(" -", str(cap)) + + parameters = None + + def __init__(self, client_id, node_handle, parameters=None): + self.parameters = parameters + Protocol.__init__(self, client_id, node_handle) + for capability_class in self.rosbridge_capabilities: + self.add_capability(capability_class) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/util/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/util/__init__.py new file mode 100644 index 000000000..8b04567e1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/util/__init__.py @@ -0,0 +1,19 @@ +# try to import json-lib: 1st try ujson, 2nd try simplejson, else import standard Python json +try: + import ujson as json +except ImportError: + try: + import simplejson as json + except ImportError: + import json # noqa: F401 + +import bson + +try: + bson.BSON +except AttributeError: + raise Exception( + "BSON installation does not support all necessary features. " + "Please use the MongoDB BSON implementation. " + "See: https://github.com/RobotWebTools/rosbridge_suite/issues/198" + ) diff --git a/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/util/cbor.py b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/util/cbor.py new file mode 100644 index 000000000..281c85415 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/src/rosbridge_library/util/cbor.py @@ -0,0 +1,457 @@ +#!python +# -*- Python -*- +# Copyright 2014-2015 Brian Olson +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import re +import struct +from io import BytesIO + +CBOR_TYPE_MASK = 0xE0 # top 3 bits +CBOR_INFO_BITS = 0x1F # low 5 bits + + +CBOR_UINT = 0x00 +CBOR_NEGINT = 0x20 +CBOR_BYTES = 0x40 +CBOR_TEXT = 0x60 +CBOR_ARRAY = 0x80 +CBOR_MAP = 0xA0 +CBOR_TAG = 0xC0 +CBOR_7 = 0xE0 # float and other types + +CBOR_UINT8_FOLLOWS = 24 # 0x18 +CBOR_UINT16_FOLLOWS = 25 # 0x19 +CBOR_UINT32_FOLLOWS = 26 # 0x1a +CBOR_UINT64_FOLLOWS = 27 # 0x1b +CBOR_VAR_FOLLOWS = 31 # 0x1f + +CBOR_BREAK = 0xFF + +CBOR_FALSE = CBOR_7 | 20 +CBOR_TRUE = CBOR_7 | 21 +CBOR_NULL = CBOR_7 | 22 +CBOR_UNDEFINED = CBOR_7 | 23 # js 'undefined' value + +CBOR_FLOAT16 = CBOR_7 | 25 +CBOR_FLOAT32 = CBOR_7 | 26 +CBOR_FLOAT64 = CBOR_7 | 27 + +CBOR_TAG_DATE_STRING = 0 # RFC3339 +CBOR_TAG_DATE_ARRAY = 1 # any number type follows, seconds since 1970-01-01T00:00:00 UTC +CBOR_TAG_BIGNUM = 2 # big endian byte string follows +CBOR_TAG_NEGBIGNUM = 3 # big endian byte string follows +CBOR_TAG_DECIMAL = 4 # [ 10^x exponent, number ] +CBOR_TAG_BIGFLOAT = 5 # [ 2^x exponent, number ] +CBOR_TAG_BASE64URL = 21 +CBOR_TAG_BASE64 = 22 +CBOR_TAG_BASE16 = 23 +CBOR_TAG_CBOR = 24 # following byte string is embedded CBOR data + +CBOR_TAG_URI = 32 +CBOR_TAG_BASE64URL = 33 +CBOR_TAG_BASE64 = 34 +CBOR_TAG_REGEX = 35 +CBOR_TAG_MIME = 36 # following text is MIME message, headers, separators and all +CBOR_TAG_CBOR_FILEHEADER = 55799 # can open a file with 0xd9d9f7 + +_CBOR_TAG_BIGNUM_BYTES = struct.pack("B", CBOR_TAG | CBOR_TAG_BIGNUM) + + +def dumps_int(val): + "return bytes representing int val in CBOR" + if val >= 0: + # CBOR_UINT is 0, so I'm lazy/efficient about not OR-ing it in. + if val <= 23: + return struct.pack("B", val) + if val <= 0x0FF: + return struct.pack("BB", CBOR_UINT8_FOLLOWS, val) + if val <= 0x0FFFF: + return struct.pack("!BH", CBOR_UINT16_FOLLOWS, val) + if val <= 0x0FFFFFFFF: + return struct.pack("!BI", CBOR_UINT32_FOLLOWS, val) + if val <= 0x0FFFFFFFFFFFFFFFF: + return struct.pack("!BQ", CBOR_UINT64_FOLLOWS, val) + outb = _dumps_bignum_to_bytearray(val) + return _CBOR_TAG_BIGNUM_BYTES + _encode_type_num(CBOR_BYTES, len(outb)) + outb + val = -1 - val + return _encode_type_num(CBOR_NEGINT, val) + + +def _dumps_bignum_to_bytearray(val): + out = [] + while val > 0: + out.insert(0, val & 0x0FF) + val = val >> 8 + return bytes(out) + + +def dumps_float(val): + return struct.pack("!Bd", CBOR_FLOAT64, val) + + +_CBOR_TAG_NEGBIGNUM_BYTES = struct.pack("B", CBOR_TAG | CBOR_TAG_NEGBIGNUM) + + +def _encode_type_num(cbor_type, val): + """For some CBOR primary type [0..7] and an auxiliary unsigned number, return CBOR encoded bytes""" + assert val >= 0 + if val <= 23: + return struct.pack("B", cbor_type | val) + if val <= 0x0FF: + return struct.pack("BB", cbor_type | CBOR_UINT8_FOLLOWS, val) + if val <= 0x0FFFF: + return struct.pack("!BH", cbor_type | CBOR_UINT16_FOLLOWS, val) + if val <= 0x0FFFFFFFF: + return struct.pack("!BI", cbor_type | CBOR_UINT32_FOLLOWS, val) + if ((cbor_type == CBOR_NEGINT) and (val <= 0x07FFFFFFFFFFFFFFF)) or ( + (cbor_type != CBOR_NEGINT) and (val <= 0x0FFFFFFFFFFFFFFFF) + ): + return struct.pack("!BQ", cbor_type | CBOR_UINT64_FOLLOWS, val) + if cbor_type != CBOR_NEGINT: + raise Exception(f"value too big for CBOR unsigned number: {val!r}") + outb = _dumps_bignum_to_bytearray(val) + return _CBOR_TAG_NEGBIGNUM_BYTES + _encode_type_num(CBOR_BYTES, len(outb)) + outb + + +def _is_unicode(val): + return isinstance(val, str) + + +def dumps_string(val, is_text=None, is_bytes=None): + if _is_unicode(val): + val = val.encode("utf8") + is_text = True + is_bytes = False + if is_bytes or is_text is not True: + return _encode_type_num(CBOR_BYTES, len(val)) + val + return _encode_type_num(CBOR_TEXT, len(val)) + val + + +def dumps_array(arr, sort_keys=False): + head = _encode_type_num(CBOR_ARRAY, len(arr)) + parts = [dumps(x, sort_keys=sort_keys) for x in arr] + return head + b"".join(parts) + + +def dumps_dict(d, sort_keys=False): + head = _encode_type_num(CBOR_MAP, len(d)) + parts = [head] + if sort_keys: + for k in sorted(d.keys()): + v = d[k] + parts.append(dumps(k, sort_keys=sort_keys)) + parts.append(dumps(v, sort_keys=sort_keys)) + else: + for k, v in d.items(): + parts.append(dumps(k, sort_keys=sort_keys)) + parts.append(dumps(v, sort_keys=sort_keys)) + return b"".join(parts) + + +def dumps_bool(b): + if b: + return struct.pack("B", CBOR_TRUE) + return struct.pack("B", CBOR_FALSE) + + +def dumps_tag(t, sort_keys=False): + return _encode_type_num(CBOR_TAG, t.tag) + dumps(t.value, sort_keys=sort_keys) + + +def _is_stringish(x): + return isinstance(x, (str, bytes)) + + +def _is_intish(x): + return isinstance(x, int) + + +def dumps(ob, sort_keys=False): + if ob is None: + return struct.pack("B", CBOR_NULL) + if isinstance(ob, bool): + return dumps_bool(ob) + if _is_stringish(ob): + return dumps_string(ob) + if isinstance(ob, (list, tuple)): + return dumps_array(ob, sort_keys=sort_keys) + # TODO: accept other enumerables and emit a variable length array + if isinstance(ob, dict): + return dumps_dict(ob, sort_keys=sort_keys) + if isinstance(ob, float): + return dumps_float(ob) + if _is_intish(ob): + return dumps_int(ob) + if isinstance(ob, Tag): + return dumps_tag(ob, sort_keys=sort_keys) + raise Exception("don't know how to cbor serialize object of type %s", type(ob)) + + +# same basic signature as json.dump, but with no options (yet) +def dump(obj, fp, sort_keys=False): + """ + obj: Python object to serialize + fp: file-like object capable of .write(bytes) + """ + # this is kinda lame, but probably not inefficient for non-huge objects + # TODO: .write() to fp as we go as each inner object is serialized + blob = dumps(obj, sort_keys=sort_keys) + fp.write(blob) + + +class Tag: + def __init__(self, tag=None, value=None): + self.tag = tag + self.value = value + + def __repr__(self): + return f"Tag({self.tag!r}, {self.value!r})" + + def __eq__(self, other): + if not isinstance(other, Tag): + return False + return (self.tag == other.tag) and (self.value == other.value) + + +def loads(data): + """ + Parse CBOR bytes and return Python objects. + """ + if data is None: + raise ValueError("got None for buffer to decode in loads") + fp = BytesIO(data) + return _loads(fp)[0] + + +def load(fp): + """ + Parse and return object from fp, a file-like object supporting .read(n) + """ + return _loads(fp)[0] + + +_MAX_DEPTH = 100 + + +def _tag_aux(fp, tb): + bytes_read = 1 + tag = tb & CBOR_TYPE_MASK + tag_aux = tb & CBOR_INFO_BITS + if tag_aux <= 23: + aux = tag_aux + elif tag_aux == CBOR_UINT8_FOLLOWS: + data = fp.read(1) + aux = struct.unpack_from("!B", data, 0)[0] + bytes_read += 1 + elif tag_aux == CBOR_UINT16_FOLLOWS: + data = fp.read(2) + aux = struct.unpack_from("!H", data, 0)[0] + bytes_read += 2 + elif tag_aux == CBOR_UINT32_FOLLOWS: + data = fp.read(4) + aux = struct.unpack_from("!I", data, 0)[0] + bytes_read += 4 + elif tag_aux == CBOR_UINT64_FOLLOWS: + data = fp.read(8) + aux = struct.unpack_from("!Q", data, 0)[0] + bytes_read += 8 + else: + assert tag_aux == CBOR_VAR_FOLLOWS, f"bogus tag {tb:02x}" + aux = None + + return tag, tag_aux, aux, bytes_read + + +def _read_byte(fp): + tb = fp.read(1) + if len(tb) == 0: + # I guess not all file-like objects do this + raise EOFError() + return ord(tb) + + +def _loads_var_array(fp, limit, depth, returntags, bytes_read): + ob = [] + tb = _read_byte(fp) + while tb != CBOR_BREAK: + (subob, sub_len) = _loads_tb(fp, tb, limit, depth, returntags) + bytes_read += 1 + sub_len + ob.append(subob) + tb = _read_byte(fp) + return (ob, bytes_read + 1) + + +def _loads_var_map(fp, limit, depth, returntags, bytes_read): + ob = {} + tb = _read_byte(fp) + while tb != CBOR_BREAK: + (subk, sub_len) = _loads_tb(fp, tb, limit, depth, returntags) + bytes_read += 1 + sub_len + (subv, sub_len) = _loads(fp, limit, depth, returntags) + bytes_read += sub_len + ob[subk] = subv + tb = _read_byte(fp) + return (ob, bytes_read + 1) + + +def _loads_array(fp, limit, depth, returntags, aux, bytes_read): + ob = [] + for i in range(aux): + subob, subpos = _loads(fp) + bytes_read += subpos + ob.append(subob) + return ob, bytes_read + + +def _loads_map(fp, limit, depth, returntags, aux, bytes_read): + ob = {} + for i in range(aux): + subk, subpos = _loads(fp) + bytes_read += subpos + subv, subpos = _loads(fp) + bytes_read += subpos + ob[subk] = subv + return ob, bytes_read + + +def _loads(fp, limit=None, depth=0, returntags=False): + "return (object, bytes read)" + if depth > _MAX_DEPTH: + raise Exception("hit CBOR loads recursion depth limit") + + tb = _read_byte(fp) + + return _loads_tb(fp, tb, limit, depth, returntags) + + +def _loads_tb(fp, tb, limit=None, depth=0, returntags=False): + # Some special cases of CBOR_7 best handled by special struct.unpack logic here + if tb == CBOR_FLOAT16: + data = fp.read(2) + hibyte, lowbyte = struct.unpack_from("BB", data, 0) + exp = (hibyte >> 2) & 0x1F + mant = ((hibyte & 0x03) << 8) | lowbyte + if exp == 0: + val = mant * (2.0**-24) + elif exp == 31: + if mant == 0: + val = float("Inf") + else: + val = float("NaN") + else: + val = (mant + 1024.0) * (2 ** (exp - 25)) + if hibyte & 0x80: + val = -1.0 * val + return (val, 3) + elif tb == CBOR_FLOAT32: + data = fp.read(4) + pf = struct.unpack_from("!f", data, 0) + return (pf[0], 5) + elif tb == CBOR_FLOAT64: + data = fp.read(8) + pf = struct.unpack_from("!d", data, 0) + return (pf[0], 9) + + tag, tag_aux, aux, bytes_read = _tag_aux(fp, tb) + + if tag == CBOR_UINT: + return (aux, bytes_read) + elif tag == CBOR_NEGINT: + return (-1 - aux, bytes_read) + elif tag == CBOR_BYTES: + ob, subpos = loads_bytes(fp, aux) + return (ob, bytes_read + subpos) + elif tag == CBOR_TEXT: + raw, subpos = loads_bytes(fp, aux, btag=CBOR_TEXT) + ob = raw.decode("utf8") + return (ob, bytes_read + subpos) + elif tag == CBOR_ARRAY: + if aux is None: + return _loads_var_array(fp, limit, depth, returntags, bytes_read) + return _loads_array(fp, limit, depth, returntags, aux, bytes_read) + elif tag == CBOR_MAP: + if aux is None: + return _loads_var_map(fp, limit, depth, returntags, bytes_read) + return _loads_map(fp, limit, depth, returntags, aux, bytes_read) + elif tag == CBOR_TAG: + ob, subpos = _loads(fp) + bytes_read += subpos + if returntags: + # Don't interpret the tag, return it and the tagged object. + ob = Tag(aux, ob) + else: + # attempt to interpret the tag and the value into a Python object. + ob = tagify(ob, aux) + return ob, bytes_read + elif tag == CBOR_7: + if tb == CBOR_TRUE: + return (True, bytes_read) + if tb == CBOR_FALSE: + return (False, bytes_read) + if tb == CBOR_NULL: + return (None, bytes_read) + if tb == CBOR_UNDEFINED: + return (None, bytes_read) + raise ValueError(f"unknown cbor tag 7 byte: {tb:02x}") + + +def loads_bytes(fp, aux, btag=CBOR_BYTES): + # TODO: limit to some maximum number of chunks and some maximum total bytes + if aux is not None: + # simple case + ob = fp.read(aux) + return (ob, aux) + # read chunks of bytes + chunklist = [] + total_bytes_read = 0 + while True: + tb = fp.read(1)[0] + if tb == CBOR_BREAK: + total_bytes_read += 1 + break + tag, tag_aux, aux, bytes_read = _tag_aux(fp, tb) + assert tag == btag, "variable length value contains unexpected component" + ob = fp.read(aux) + chunklist.append(ob) + total_bytes_read += bytes_read + aux + return (b"".join(chunklist), total_bytes_read) + + +def _bytes_to_biguint(bs): + out = 0 + for ch in bs: + out = out << 8 + out = out | ch + return out + + +def tagify(ob, aux): + # TODO: make this extensible? + # cbor.register_tag_handler(tagnumber, tag_handler) + # where tag_handler takes (tagnumber, tagged_object) + if aux == CBOR_TAG_DATE_STRING: + # TODO: parse RFC3339 date string + pass + if aux == CBOR_TAG_DATE_ARRAY: + return datetime.datetime.utcfromtimestamp(ob) + if aux == CBOR_TAG_BIGNUM: + return _bytes_to_biguint(ob) + if aux == CBOR_TAG_NEGBIGNUM: + return -1 - _bytes_to_biguint(ob) + if aux == CBOR_TAG_REGEX: + # Is this actually a good idea? Should we just return the tag and the raw value to the user somehow? + return re.compile(ob) + return Tag(aux, ob) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_advertise.py b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_advertise.py new file mode 100755 index 000000000..34cd117a8 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_advertise.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +import unittest +from json import dumps, loads +from time import sleep + +import rospy +import rostest +from rosbridge_library.capabilities.advertise import Advertise +from rosbridge_library.internal import ros_loader +from rosbridge_library.internal.publishers import manager +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, + Protocol, +) + + +class TestAdvertise(unittest.TestCase): + def setUp(self): + rospy.init_node("test_advertise") + manager.unregister_timeout = 1.0 + + def is_topic_published(self, topicname): + return topicname in dict(rospy.get_published_topics()).keys() + + def test_missing_arguments(self): + proto = Protocol("hello") + adv = Advertise(proto) + msg = {"op": "advertise"} + self.assertRaises(MissingArgumentException, adv.advertise, loads(dumps(msg))) + + msg = {"op": "advertise", "topic": "/jon"} + self.assertRaises(MissingArgumentException, adv.advertise, loads(dumps(msg))) + + msg = {"op": "advertise", "type": "std_msgs/String"} + self.assertRaises(MissingArgumentException, adv.advertise, loads(dumps(msg))) + + def test_invalid_arguments(self): + proto = Protocol("hello") + adv = Advertise(proto) + + msg = {"op": "advertise", "topic": 3, "type": "std_msgs/String"} + self.assertRaises(InvalidArgumentException, adv.advertise, loads(dumps(msg))) + + msg = {"op": "advertise", "topic": "/jon", "type": 3} + self.assertRaises(InvalidArgumentException, adv.advertise, loads(dumps(msg))) + + def test_invalid_msg_typestrings(self): + invalid = [ + "", + "/", + "//", + "///", + "////", + "/////", + "bad", + "stillbad", + "not/better/still", + "not//better//still", + "not///better///still", + "better/", + "better//", + "better///", + "/better", + "//better", + "///better", + r"this\isbad", + "\\", + ] + + proto = Protocol("hello") + adv = Advertise(proto) + + for invalid_type in invalid: + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_typestrings", + "type": invalid_type, + } + self.assertRaises( + ros_loader.InvalidTypeStringException, adv.advertise, loads(dumps(msg)) + ) + + def test_invalid_msg_package(self): + nonexistent = [ + "wangle_msgs/Jam", + "whistleblower_msgs/Document", + "coercion_msgs/Bribe", + "airconditioning_msgs/Cold", + "pr2thoughts_msgs/Escape", + ] + + proto = Protocol("hello") + adv = Advertise(proto) + + for invalid_type in nonexistent: + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_package", + "type": invalid_type, + } + self.assertRaises(ros_loader.InvalidPackageException, adv.advertise, loads(dumps(msg))) + + def test_invalid_msg_module(self): + no_msgs = [ + "roslib/Time", + "roslib/Duration", + "roslib/Header", + "std_srvs/ConflictedMsg", + "topic_tools/MessageMessage", + ] + + proto = Protocol("hello") + adv = Advertise(proto) + + for invalid_type in no_msgs: + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_module", + "type": invalid_type, + } + self.assertRaises(ros_loader.InvalidModuleException, adv.advertise, loads(dumps(msg))) + + def test_invalid_msg_classes(self): + nonexistent = [ + "roscpp/Time", + "roscpp/Duration", + "roscpp/Header", + "rospy/Time", + "rospy/Duration", + "rospy/Header", + "std_msgs/Spool", + "geometry_msgs/Tetrahedron", + "sensor_msgs/TelepathyUnit", + ] + + proto = Protocol("hello") + adv = Advertise(proto) + + for invalid_type in nonexistent: + msg = { + "op": "advertise", + "topic": "/test_invalid_msg_classes", + "type": invalid_type, + } + self.assertRaises(ros_loader.InvalidClassException, adv.advertise, loads(dumps(msg))) + + def test_valid_msg_classes(self): + assortedmsgs = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "std_msgs/String", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] + + proto = Protocol("hello") + adv = Advertise(proto) + + for valid_type in assortedmsgs: + msg = {"op": "advertise", "topic": "/" + valid_type, "type": valid_type} + adv.advertise(loads(dumps(msg))) + adv.unadvertise(loads(dumps(msg))) + + def test_do_advertise(self): + proto = Protocol("hello") + adv = Advertise(proto) + topic = "/test_do_advertise" + type = "std_msgs/String" + + msg = {"op": "advertise", "topic": topic, "type": type} + adv.advertise(loads(dumps(msg))) + self.assertTrue(self.is_topic_published(topic)) + adv.unadvertise(loads(dumps(msg))) + self.assertTrue(self.is_topic_published(topic)) + sleep(manager.unregister_timeout * 1.1) + self.assertFalse(self.is_topic_published(topic)) + + +PKG = "rosbridge_library" +NAME = "test_advertise" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestAdvertise) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_call_service.py b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_call_service.py new file mode 100755 index 000000000..4c2280a4c --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_call_service.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +import time +import unittest +from json import dumps, loads + +import rospy +import rostest +from rosbridge_library.capabilities.call_service import CallService +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, + Protocol, +) +from roscpp.srv import GetLoggers +from std_srvs.srv import SetBool + + +class TestCallService(unittest.TestCase): + def setUp(self): + rospy.init_node("test_call_service") + + def test_missing_arguments(self): + proto = Protocol("test_missing_arguments") + s = CallService(proto) + msg = loads(dumps({"op": "call_service"})) + self.assertRaises(MissingArgumentException, s.call_service, msg) + + def test_invalid_arguments(self): + proto = Protocol("test_invalid_arguments") + s = CallService(proto) + + msg = loads(dumps({"op": "call_service", "service": 3})) + self.assertRaises(InvalidArgumentException, s.call_service, msg) + + def test_call_service_works(self): + # Prepare to call the service the 'proper' way + p = rospy.ServiceProxy(rospy.get_name() + "/get_loggers", GetLoggers) + p.wait_for_service() + time.sleep(1.0) + + proto = Protocol("test_call_service_works") + s = CallService(proto) + msg = loads(dumps({"op": "call_service", "service": rospy.get_name() + "/get_loggers"})) + + received = {"msg": None, "arrived": False} + + def cb(msg, cid=None): + received["msg"] = msg + received["arrived"] = True + + proto.send = cb + + s.call_service(msg) + + timeout = 5.0 + start = rospy.Time.now() + while rospy.Time.now() - start < rospy.Duration(timeout): + if received["arrived"]: + break + time.sleep(0.1) + + # The rosbridge service call actually causes another logger to appear, + # so do the "regular" service call after that. + ret = p() + + self.assertTrue(received["msg"]["result"]) + for x, y in zip(ret.loggers, received["msg"]["values"]["loggers"]): + self.assertEqual(x.name, y["name"]) + self.assertEqual(x.level, y["level"]) + + def test_call_service_fail(self): + # Dummy service that instantly fails + _ = rospy.Service("set_bool_fail", SetBool, lambda req: None) + + proto = Protocol("test_call_service_fail") + s = CallService(proto) + send_msg = loads( + dumps( + { + "op": "call_service", + "service": rospy.get_name() + "/set_bool_fail", + "args": "[ true ]", + } + ) + ) + + received = {"msg": None, "arrived": False} + + def cb(msg, cid=None): + received["msg"] = msg + received["arrived"] = True + + proto.send = cb + + s.call_service(send_msg) + + timeout = 5.0 + start = rospy.Time.now() + while rospy.Time.now() - start < rospy.Duration(timeout): + if received["arrived"]: + break + time.sleep(0.1) + + self.assertFalse(received["msg"]["result"]) + + +PKG = "rosbridge_library" +NAME = "test_call_service" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestCallService) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_publish.py b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_publish.py new file mode 100755 index 000000000..3e43a6b7a --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_publish.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +import unittest +from json import dumps, loads +from time import sleep + +import rospy +import rostest +from rosbridge_library.capabilities.publish import Publish +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, + Protocol, +) +from std_msgs.msg import String + + +class TestAdvertise(unittest.TestCase): + def setUp(self): + rospy.init_node("test_advertise") + + def test_missing_arguments(self): + proto = Protocol("hello") + pub = Publish(proto) + msg = {"op": "publish"} + self.assertRaises(MissingArgumentException, pub.publish, msg) + + msg = {"op": "publish", "msg": {}} + self.assertRaises(MissingArgumentException, pub.publish, msg) + + def test_invalid_arguments(self): + proto = Protocol("hello") + pub = Publish(proto) + + msg = {"op": "publish", "topic": 3} + self.assertRaises(InvalidArgumentException, pub.publish, msg) + + def test_publish_works(self): + proto = Protocol("hello") + pub = Publish(proto) + topic = "/test_publish_works" + msg = {"data": "test publish works"} + + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + rospy.Subscriber(topic, String, cb) + + pub_msg = loads(dumps({"op": "publish", "topic": topic, "msg": msg})) + pub.publish(pub_msg) + + sleep(0.5) + self.assertEqual(received["msg"].data, msg["data"]) + + +PKG = "rosbridge_library" +NAME = "test_publish" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestAdvertise) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_service_capabilities.py b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_service_capabilities.py new file mode 100755 index 000000000..ad9b8b859 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_service_capabilities.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python +import unittest +from json import dumps, loads + +import rospy +import rostest +from rosbridge_library.capabilities.advertise_service import AdvertiseService +from rosbridge_library.capabilities.call_service import CallService +from rosbridge_library.capabilities.service_response import ServiceResponse +from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, + Protocol, +) + + +class TestServiceCapabilities(unittest.TestCase): + def setUp(self): + self.proto = Protocol(self._testMethodName) + # change the log function so we can verify errors are logged + self.proto.log = self.mock_log + # change the send callback so we can access the rosbridge messages + # being sent + self.proto.send = self.local_send_cb + self.advertise = AdvertiseService(self.proto) + self.unadvertise = UnadvertiseService(self.proto) + self.response = ServiceResponse(self.proto) + self.received_message = None + self.log_entries = [] + + def local_send_cb(self, msg): + self.received_message = msg + + def mock_log(self, loglevel, message, _=None): + self.log_entries.append((loglevel, message)) + + def test_advertise_missing_arguments(self): + advertise_msg = loads(dumps({"op": "advertise_service"})) + self.assertRaises(MissingArgumentException, self.advertise.advertise_service, advertise_msg) + + def test_advertise_invalid_arguments(self): + advertise_msg = loads(dumps({"op": "advertise_service", "type": 42, "service": None})) + self.assertRaises(InvalidArgumentException, self.advertise.advertise_service, advertise_msg) + + def test_response_missing_arguments(self): + response_msg = loads(dumps({"op": "service_response"})) + self.assertRaises(MissingArgumentException, self.response.service_response, response_msg) + + # this message has the optional fields, with correct types, but not the + # required ones + response_msg = loads( + dumps({"op": "service_response", "id": "dummy_service", "values": "none"}) + ) + self.assertRaises(MissingArgumentException, self.response.service_response, response_msg) + + def test_response_invalid_arguments(self): + response_msg = loads(dumps({"op": "service_response", "service": 5, "result": "error"})) + self.assertRaises(InvalidArgumentException, self.response.service_response, response_msg) + + def test_advertise_service(self): + service_path = "/set_bool_1" + advertise_msg = loads( + dumps( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": service_path, + } + ) + ) + self.advertise.advertise_service(advertise_msg) + + # This throws an exception if the timeout is exceeded (i.e. the service + # is not properly advertised) + rospy.wait_for_service(service_path, 1.0) + + def test_call_advertised_service(self): + service_path = "/set_bool_2" + advertise_msg = loads( + dumps( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": service_path, + } + ) + ) + self.advertise.advertise_service(advertise_msg) + + # Call the service via rosbridge because rospy.ServiceProxy.call() is + # blocking + call_service = CallService(self.proto) + call_service.call_service( + loads( + dumps( + { + "op": "call_service", + "id": "foo", + "service": service_path, + "args": [True], + } + ) + ) + ) + + loop_iterations = 0 + while self.received_message is None: + rospy.sleep(rospy.Duration(0.5)) + loop_iterations += 1 + if loop_iterations > 3: + self.fail( + "did not receive service call rosbridge message " "after waiting 2 seconds" + ) + + self.assertFalse(self.received_message is None) + self.assertTrue("op" in self.received_message) + self.assertTrue(self.received_message["op"] == "call_service") + self.assertTrue("id" in self.received_message) + + # Now send the response + response_msg = loads( + dumps( + { + "op": "service_response", + "service": service_path, + "id": self.received_message["id"], + "values": {"success": True, "message": ""}, + "result": True, + } + ) + ) + self.received_message = None + self.response.service_response(response_msg) + + loop_iterations = 0 + while self.received_message is None: + rospy.sleep(rospy.Duration(0.5)) + loop_iterations += 1 + if loop_iterations > 3: + self.fail( + "did not receive service response rosbridge message " "after waiting 2 seconds" + ) + + self.assertFalse(self.received_message is None) + # Rosbridge should forward the response message to the "client" + # (i.e. our custom send function, see setUp()) + self.assertEqual(self.received_message["op"], "service_response") + self.assertTrue(self.received_message["result"]) + + def test_unadvertise_with_live_request(self): + service_path = "/set_bool_3" + advertise_msg = loads( + dumps( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": service_path, + } + ) + ) + self.advertise.advertise_service(advertise_msg) + + # Call the service via rosbridge because rospy.ServiceProxy.call() is + # blocking + call_service = CallService(self.proto) + call_service.call_service( + loads( + dumps( + { + "op": "call_service", + "id": "foo", + "service": service_path, + "args": [True], + } + ) + ) + ) + + loop_iterations = 0 + while self.received_message is None: + rospy.sleep(rospy.Duration(0.5)) + loop_iterations += 1 + if loop_iterations > 3: + self.fail( + "did not receive service call rosbridge message " "after waiting 2 seconds" + ) + + self.assertFalse(self.received_message is None) + self.assertTrue("op" in self.received_message) + self.assertTrue(self.received_message["op"] == "call_service") + self.assertTrue("id" in self.received_message) + + # Now send the response + response_msg = loads(dumps({"op": "unadvertise_service", "service": service_path})) + self.received_message = None + self.unadvertise.unadvertise_service(response_msg) + + loop_iterations = 0 + while self.received_message is None: + rospy.sleep(rospy.Duration(0.5)) + loop_iterations += 1 + if loop_iterations > 3: + self.fail( + "did not receive service response rosbridge message " "after waiting 2 seconds" + ) + + self.assertFalse(self.received_message is None) + # Rosbridge should abort the existing service call with an error + # (i.e. "result" should be False) + self.assertEqual(self.received_message["op"], "service_response") + self.assertFalse(self.received_message["result"]) + + +PKG = "rosbridge_library" +NAME = "test_service_capabilities" +if __name__ == "__main__": + rospy.init_node(NAME) + rostest.rosrun(PKG, NAME, TestServiceCapabilities) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_subscribe.py b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_subscribe.py new file mode 100755 index 000000000..cb1035524 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/capabilities/test_subscribe.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +import time +import unittest +from json import dumps, loads + +import rospy +import rostest +from rosbridge_library.capabilities import subscribe +from rosbridge_library.protocol import ( + InvalidArgumentException, + MissingArgumentException, + Protocol, +) +from std_msgs.msg import String + + +class TestSubscribe(unittest.TestCase): + def setUp(self): + rospy.init_node("test_subscribe") + + def dummy_cb(self, msg): + pass + + def test_update_params(self): + """Adds a bunch of random clients to the subscription and sees whether + the correct parameters are chosen as the min""" + client_id = "client_test_update_params" + topic = "/test_update_params" + msg_type = "std_msgs/String" + + subscription = subscribe.Subscription(client_id, topic, None) + + min_throttle_rate = 5 + min_queue_length = 2 + min_frag_size = 20 + + for throttle_rate in range(min_throttle_rate, min_throttle_rate + 10): + for queue_length in range(min_queue_length, min_queue_length + 10): + for frag_size in range(min_frag_size, min_frag_size + 10): + sid = throttle_rate * 100 + queue_length * 10 + frag_size + subscription.subscribe(sid, msg_type, throttle_rate, queue_length, frag_size) + + subscription.update_params() + + try: + self.assertEqual(subscription.throttle_rate, min_throttle_rate) + self.assertEqual(subscription.queue_length, min_queue_length) + self.assertEqual(subscription.fragment_size, min_frag_size) + self.assertEqual(subscription.compression, "none") + + list(subscription.clients.values())[0]["compression"] = "png" + + subscription.update_params() + + self.assertEqual(subscription.throttle_rate, min_throttle_rate) + self.assertEqual(subscription.queue_length, min_queue_length) + self.assertEqual(subscription.fragment_size, min_frag_size) + self.assertEqual(subscription.compression, "png") + finally: + subscription.unregister() + + def test_missing_arguments(self): + proto = Protocol("test_missing_arguments") + sub = subscribe.Subscribe(proto) + msg = {"op": "subscribe"} + self.assertRaises(MissingArgumentException, sub.subscribe, msg) + + def test_invalid_arguments(self): + proto = Protocol("test_invalid_arguments") + sub = subscribe.Subscribe(proto) + + msg = {"op": "subscribe", "topic": 3} + self.assertRaises(InvalidArgumentException, sub.subscribe, msg) + + msg = {"op": "subscribe", "topic": "/jon", "type": 3} + self.assertRaises(InvalidArgumentException, sub.subscribe, msg) + + msg = {"op": "subscribe", "topic": "/jon", "throttle_rate": "fast"} + self.assertRaises(InvalidArgumentException, sub.subscribe, msg) + + msg = {"op": "subscribe", "topic": "/jon", "fragment_size": "five cubits"} + self.assertRaises(InvalidArgumentException, sub.subscribe, msg) + + msg = {"op": "subscribe", "topic": "/jon", "queue_length": "long"} + self.assertRaises(InvalidArgumentException, sub.subscribe, msg) + + msg = {"op": "subscribe", "topic": "/jon", "compression": 9000} + self.assertRaises(InvalidArgumentException, sub.subscribe, msg) + + def test_subscribe_works(self): + proto = Protocol("test_subscribe_works") + sub = subscribe.Subscribe(proto) + topic = "/test_subscribe_works" + msg = String() + msg.data = "test test_subscribe_works works" + msg_type = "std_msgs/String" + + received = {"msg": None} + + def send(outgoing, **kwargs): + received["msg"] = outgoing + + proto.send = send + + sub.subscribe(loads(dumps({"op": "subscribe", "topic": topic, "type": msg_type}))) + + p = rospy.Publisher(topic, String, queue_size=5) + time.sleep(0.25) + p.publish(msg) + + time.sleep(0.25) + self.assertEqual(received["msg"]["msg"]["data"], msg.data) + + +PKG = "rosbridge_library" +NAME = "test_subscribe" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestSubscribe) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py new file mode 100755 index 000000000..673c3164a --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_client_complex-srv.py @@ -0,0 +1,143 @@ +#!/usr/bin/python +import socket + +from rosbridge_library.util import json + +# ##################### variables begin ######################################## +# these parameters should be changed to match the actual environment # +# ############################################################################## + +client_socket_timeout = 6 # seconds +max_msg_length = 2000000 # bytes + +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer + +service_name = "nested_srv" # service name +# request_byte_count = 5000 +receiving_fragment_size = 1000 +receive_message_intervall = 0.0 + +# ##################### variables end ########################################## + + +# ############################################################################## + + +def request_service(): + service_request_object = { + "op": "call_service", # op-code for rosbridge + "service": "/" + service_name, # select service + "fragment_size": receiving_fragment_size, # optional: tells rosbridge to send fragments if message size is bigger than requested + "message_intervall": receive_message_intervall, + "args": { + "pose": { + "position": {"y": 0.0, "x": 0.0, "z": 0.0}, + "orientation": {"y": 0.0, "x": 0.0, "z": 0.0, "w": 0.0}, + } + } + # "count" : request_byte_count # count is the parameter for send_bytes as defined in srv-file (always put into args field!) + } + service_request = json.dumps(service_request_object) + print("sending JSON-message to rosbridge:", service_request) + sock.send(service_request) + + +# ############################################################################## + + +# ##################### script begin ########################################### +# should not need to be changed (but could be improved ;) ) # +# ############################################################################## +try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + sock.settimeout(client_socket_timeout) + sock.connect((rosbridge_ip, rosbridge_port)) + + request_service() # send service_request + + incoming = None + buffer = "" + done = False + result = None + reconstructed = None + # should not need a loop (maximum wait can be set by client_socket_timeout), + # but since its for test/demonstration only .. leave it as it is for now + while not done: + try: + incoming = sock.recv(max_msg_length) # receive service_response from rosbridge + if buffer == "": + buffer = incoming + if incoming == "": + print("closing socket") + sock.close() + break + else: + buffer = buffer + incoming + # print "buffer-length:", len(buffer) + try: # try to access service_request directly (not fragmented) + data_object = json.loads(buffer) + if data_object["op"] == "service_response": + reconstructed = buffer + done = True + except Exception: + # print "direct access to JSON failed.." + # print(e) + pass + try: + # print "defragmenting incoming messages" + result_string = buffer.split( + "}{" + ) # split buffer into fragments and re-fill curly brackets + result = [] + for fragment in result_string: + if fragment[0] != "{": + fragment = "{" + fragment + if fragment[len(fragment) - 1] != "}": + fragment = fragment + "}" + try: + result.append( + json.loads(fragment) + ) # try to parse json from string, and append if successful + except Exception: + # print(e) + # print result_string + raise # re-raise the last exception, allows to see and continue with processing of exception + + fragment_count = len(result) + print("fragment_count:", fragment_count) + announced = int(result[0]["total"]) + if fragment_count == announced: # if all fragments received --> sort and defragment + # sort fragments + sorted_result = [None] * fragment_count + unsorted_result = [] + for fragment in result: + unsorted_result.append(fragment) + sorted_result[int(fragment["num"])] = fragment + reconstructed = "" + for fragment in sorted_result: + reconstructed = reconstructed + fragment["data"] + done = True + except Exception: + # print(e) + pass + except Exception: + # print(e) + pass + + returned_data = json.loads( + reconstructed + ) # when service response is received --> access it (as defined in srv-file) + if returned_data["values"] is None: + print("response was None -> service was not available") + else: + print("received:") + print( + returned_data + ) # ["values"]#["data"].decode('base64','strict') # decode values-field + +except Exception as e: + print("ERROR - could not receive service_response") + print(e) + +sock.close() diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py new file mode 100755 index 000000000..b8dc95985 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/complex_srv+tcp/test_non-ros_service_server_complex-srv.py @@ -0,0 +1,256 @@ +#!/usr/bin/python +import socket +import sys +import time +from random import randint + +from rosbridge_library.util import json + +# ##################### variables begin ######################################## +# these parameters should be changed to match the actual environment # +# ############################################################################## + +tcp_socket_timeout = 10 # seconds +max_msg_length = 20000 # bytes + +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer + +service_type = "rosbridge_test_msgs/TestNestedService" # make sure this matches an existing service type on rosbridge-server (in specified srv_module) +service_name = "nested_srv" # service name + +send_fragment_size = 1000 +# delay between sends to rosbridge is not needed anymore, if using my version of protocol (uses buffer to collect data from stream) +send_fragment_delay = 0.000 # 1 +receive_fragment_size = 10 +receive_message_intervall = 0.0 + +# ##################### variables end ########################################## + + +# ##################### service_calculation begin ############################## +# change this function to match whatever service should be provided # +# ############################################################################## + + +def calculate_service_response(request): + request_object = json.loads(request) # parse string for service request + # args = request_object["args"] # get parameter field (args) # unused variable + # count = int(args["count"] ) # get parameter(s) as described in corresponding ROS srv-file + # + # message = "" # calculate service response + # for i in range(0,count): + # message += str(chr(randint(32,126))) + # if i% 100000 == 0: + # print count - i, "bytes left to generate" + + message = {"data": {"data": 42.0}} + + """ + IMPORTANT! + use base64 encoding to avoid JSON-parsing problems! + --> use .decode("base64","strict") at client side + """ + # message = message.encode('base64','strict') + service_response_data = message # service response (as defined in srv-file) + + response_object = { + "op": "service_response", + "id": request_object["id"], + "data": service_response_data, # put service response in "data"-field of response object (in this case it's twice "data", because response value is also named data (in srv-file) + } + response_message = json.dumps(response_object) + return response_message + + +# ##################### service_calculation end ################################ + + +# ##################### helper functions / and variables begin ################# +# should not need to be changed (but could be improved ) # +# ############################################################################## + +buffer = "" + + +def connect_tcp_socket(): + tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + tcp_sock.settimeout(tcp_socket_timeout) + tcp_sock.connect((rosbridge_ip, rosbridge_port)) + return tcp_sock + + +def advertise_service(): # advertise service + advertise_message_object = { + "op": "advertise_service", + "type": service_type, + "service": service_name, + "fragment_size": receive_fragment_size, + "message_intervall": receive_message_intervall, + } + advertise_message = json.dumps(advertise_message_object) + tcp_socket.send(str(advertise_message)) + + +def unadvertise_service(): # unadvertise service + unadvertise_message_object = {"op": "unadvertise_service", "service": service_name} + unadvertise_message = json.dumps(unadvertise_message_object) + tcp_socket.send(str(unadvertise_message)) + + +def wait_for_service_request(): # receive data from rosbridge + data = None + global buffer + + try: + done = False + global buffer + while not done: + incoming = tcp_socket.recv(max_msg_length) # get data from socket + if incoming == "": + print("connection closed by peer") + sys.exit(1) + buffer = buffer + incoming # append data to buffer + try: # try to parse JSON from buffer + data_object = json.loads(buffer) + if data_object["op"] == "call_service": + data = buffer + done = True + return data # if parsing was successful --> return data string + except Exception: + # print "direct_access error:" + # print(e) + pass + + # print "trying to defragment" + try: # opcode was not "call_service" -> try to defragment + result_string = buffer.split( + "}{" + ) # split buffer into fragments and re-fill with curly brackets + result = [] + for fragment in result_string: + if fragment[0] != "{": + fragment = "{" + fragment + if fragment[len(fragment) - 1] != "}": + fragment = fragment + "}" + result.append(json.loads(fragment)) + + try: # try to defragment when received all fragments + fragment_count = len(result) + announced = int(result[0]["total"]) + + if fragment_count == announced: + reconstructed = "" + sorted_result = [None] * fragment_count # sort fragments.. + unsorted_result = [] + for fragment in result: + unsorted_result.append(fragment) + sorted_result[int(fragment["num"])] = fragment + + for fragment in sorted_result: # reconstruct from fragments + reconstructed = reconstructed + fragment["data"] + + # print "reconstructed", reconstructed + buffer = "" # empty buffer + done = True + print("reconstructed message from", len(result), "fragments") + # print reconstructed + return reconstructed + except Exception as e: + print("not possible to defragment:", buffer) + print(e) + except Exception as e: + print("defrag_error:", buffer) + print(e) + pass + except Exception: + # print "network-error(?):", e + pass + return data + + +def send_service_response(response): # send response to rosbridge + tcp_socket.send(response) + + +def list_of_fragments(full_message, fragment_size): # create fragment messages for a huge message + message_id = randint(0, 64000) # generate random message id + fragments = [] # generate list of data fragments + cursor = 0 + while cursor < len(full_message): + fragment_begin = cursor + if len(full_message) < cursor + fragment_size: + fragment_end = len(full_message) + cursor = len(full_message) + else: + fragment_end = cursor + fragment_size + cursor += fragment_size + fragment = full_message[fragment_begin:fragment_end] + fragments.append(fragment) + + fragmented_messages_list = [] # generate list of fragmented messages (including headers) + if len(fragments) > 1: + for count, fragment in enumerate(fragments): # iterate through list and have index counter + fragmented_message_object = { + "op": "fragment", # create Python-object for each fragment message + "id": str(message_id), + "data": str(fragment), + "num": count, + "total": len(fragments), + } + fragmented_message = json.dumps( + fragmented_message_object + ) # create JSON-object from python-object for each fragment message + fragmented_messages_list.append( + fragmented_message + ) # append JSON-object to list of fragmented messages + else: # if only 1 fragment --> do not send as fragment, but as service_response + fragmented_messages_list.append(str(fragment)) + return fragmented_messages_list # return list of 'ready-to-send' fragmented messages + + +# ##################### helper functions end ################################### + + +# ##################### script begin ########################################### +# should not need to be changed (but could be improved ) # +# ############################################################################## + +tcp_socket = connect_tcp_socket() # open tcp_socket +advertise_service() # advertise service in ROS (via rosbridge) +print("service provider started and waiting for requests") + +try: # allows to catch KeyboardInterrupt + while True: # loop forever (or until ctrl-c is pressed) + data = None + try: # allows to catch any Exception (network, json, ..) + data = wait_for_service_request() # receive request from rosbridge + if data == "": # exit on empty string + break + elif data: # received service_request (or at least some data..) + response = calculate_service_response(data) # generate service_response + + print("response calculated, now splitting into fragments..") + fragment_list = list_of_fragments( + response, send_fragment_size + ) # generate fragments to send to rosbridge + + print("sending", len(fragment_list), "messages as response") + for fragment in fragment_list: + # print "sending:" ,fragment + send_service_response( + fragment + ) # send service_response to rosbridge (or fragments; just send any list entry) + time.sleep( + send_fragment_delay + ) # (not needed if using patched rosbridge protocol.py) + except Exception as e: + print(e) + pass +except KeyboardInterrupt: + try: + unadvertise_service() # unadvertise service + tcp_socket.close() # close tcp_socket + except Exception as e: + print(e) + print('non-ros_service_server stopped because user pressed "Ctrl-C"') diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py new file mode 100755 index 000000000..368d6c04c --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_client_fragmented.py @@ -0,0 +1,137 @@ +#!/usr/bin/python +import socket + +from rosbridge_library.util import json + +# ##################### variables begin ######################################## +# these parameters should be changed to match the actual environment # +# ############################################################################## + +client_socket_timeout = 6 # seconds +max_msg_length = 2000000 # bytes + +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer + +service_name = "send_bytes" # service name +request_byte_count = 500000 # NOTE: receiving more than ~100.000 bytes without setting a fragment_size was not possible during testing. +receiving_fragment_size = 1000 +receive_message_intervall = 0.0 + +# ##################### variables end ########################################## + + +# ############################################################################## + + +def request_service(): + service_request_object = { + "op": "call_service", # op-code for rosbridge + "service": "/" + service_name, # select service + "fragment_size": receiving_fragment_size, # optional: tells rosbridge to send fragments if message size is bigger than requested + "message_intervall": receive_message_intervall, + "args": { + "count": request_byte_count # count is the parameter for send_bytes as defined in srv-file (always put into args field!) + }, + } + service_request = json.dumps(service_request_object) + print("sending JSON-message to rosbridge:", service_request) + sock.send(service_request) + + +# ############################################################################## + + +# ##################### script begin ########################################### +# should not need to be changed (but could be improved ;) ) # +# ############################################################################## +try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + sock.settimeout(client_socket_timeout) + sock.connect((rosbridge_ip, rosbridge_port)) + + request_service() # send service_request + + incoming = None + buffer = "" + done = False + result = None + reconstructed = None + # should not need a loop (maximum wait can be set by client_socket_timeout), + # but since its for test/demonstration only .. leave it as it is for now + while not done: + try: + incoming = sock.recv(max_msg_length) # receive service_response from rosbridge + if buffer == "": + buffer = incoming + if incoming == "": + print("closing socket") + sock.close() + break + else: + buffer = buffer + incoming + # print "buffer-length:", len(buffer) + try: # try to access service_request directly (not fragmented) + data_object = json.loads(buffer) + if data_object["op"] == "service_response": + reconstructed = buffer + done = True + except Exception: + # print "direct access to JSON failed.." + # print(e) + pass + try: + # print "defragmenting incoming messages" + result_string = buffer.split( + "}{" + ) # split buffer into fragments and re-fill curly brackets + result = [] + for fragment in result_string: + if fragment[0] != "{": + fragment = "{" + fragment + if fragment[len(fragment) - 1] != "}": + fragment = fragment + "}" + try: + result.append( + json.loads(fragment) + ) # try to parse json from string, and append if successful + except Exception: + # print(e) + # print result_string + raise # re-raise the last exception, allows to see and continue with processing of exception + + fragment_count = len(result) + print("fragment_count:", fragment_count) + announced = int(result[0]["total"]) + if fragment_count == announced: # if all fragments received --> sort and defragment + # sort fragments + sorted_result = [None] * fragment_count + unsorted_result = [] + for fragment in result: + unsorted_result.append(fragment) + sorted_result[int(fragment["num"])] = fragment + reconstructed = "" + for fragment in sorted_result: + reconstructed = reconstructed + fragment["data"] + done = True + except Exception: + # print(e) + pass + except Exception: + # print(e) + pass + + returned_data = json.loads( + reconstructed + ) # when service response is received --> access it (as defined in srv-file) + if returned_data["values"] is None: + print("response was None -> service was not available") + else: + print("received:") + print(returned_data["values"]["data"].decode("base64", "strict")) # decode values-field + +except Exception as e: + print("ERROR - could not receive service_response") + print(e) + +sock.close() diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py new file mode 100755 index 000000000..05ffb04b0 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/experimental/fragmentation+srv+tcp/test_non-ros_service_server_fragmented.py @@ -0,0 +1,258 @@ +#!/usr/bin/python +import socket +import sys +import time +from random import randint + +from rosbridge_library.util import json + +# ##################### variables begin ######################################## +# these parameters should be changed to match the actual environment # +# ############################################################################## + +tcp_socket_timeout = 10 # seconds +max_msg_length = 20000 # bytes + +rosbridge_ip = "localhost" # hostname or ip +rosbridge_port = 9090 # port as integer + +service_type = "rosbridge_test_msgs/SendBytes" # make sure this matches an existing service type on rosbridge-server (in specified srv_module) +service_name = "send_bytes" # service name + +send_fragment_size = 1000 +# delay between sends to rosbridge is not needed anymore, if using my version of +# protocol (uses buffer to collect data from stream) +send_fragment_delay = 0.000 # 1 +receive_fragment_size = 10 +receive_message_intervall = 0.0 + +# ##################### variables end ########################################## + + +# ##################### service_calculation begin ############################## +# change this function to match whatever service should be provided # +# ############################################################################## + + +def calculate_service_response(request): + request_object = json.loads(request) # parse string for service request + args = request_object["args"] # get parameter field (args) + count = int(args["count"]) # get parameter(s) as described in corresponding ROS srv-file + + message = "" + # calculate service response + for i in range(0, count): + # message += str(chr(randint(32,126))) + message += str(chr(randint(32, 126))) + if i % 100000 == 0: + print(count - i, "bytes left to generate") + + """ + IMPORTANT! + use base64 encoding to avoid JSON-parsing problems! + --> use .decode("base64","strict") at client side + """ + message = message.encode("base64", "strict") + service_response_data = {"data": message} # service response (as defined in srv-file) + + response_object = { + "op": "service_response", + "id": request_object["id"], + "service": service_name, + "values": service_response_data, # put service response in "data"-field of response object (in this case it's twice "data", because response value is also named data (in srv-file) + } + response_message = json.dumps(response_object) + return response_message + + +# ##################### service_calculation end ################################ + + +# ##################### helper functions / and variables begin ################# +# should not need to be changed (but could be improved ) # +# ############################################################################## + +buffer = "" + + +def connect_tcp_socket(): + tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # connect to rosbridge + tcp_sock.settimeout(tcp_socket_timeout) + tcp_sock.connect((rosbridge_ip, rosbridge_port)) + return tcp_sock + + +def advertise_service(): # advertise service + advertise_message_object = { + "op": "advertise_service", + "type": service_type, + "service": service_name, + "fragment_size": receive_fragment_size, + "message_intervall": receive_message_intervall, + } + advertise_message = json.dumps(advertise_message_object) + tcp_socket.send(str(advertise_message)) + + +def unadvertise_service(): # unadvertise service + unadvertise_message_object = {"op": "unadvertise_service", "service": service_name} + unadvertise_message = json.dumps(unadvertise_message_object) + tcp_socket.send(str(unadvertise_message)) + + +def wait_for_service_request(): # receive data from rosbridge + data = None + global buffer + + try: + done = False + global buffer + while not done: + incoming = tcp_socket.recv(max_msg_length) # get data from socket + if incoming == "": + print("connection closed by peer") + sys.exit(1) + buffer = buffer + incoming # append data to buffer + try: # try to parse JSON from buffer + data_object = json.loads(buffer) + if data_object["op"] == "call_service": + data = buffer + done = True + return data # if parsing was successful --> return data string + except Exception: + # print "direct_access error:" + # print(e) + pass + + # print "trying to defragment" + try: # opcode was not "call_service" -> try to defragment + result_string = buffer.split( + "}{" + ) # split buffer into fragments and re-fill with curly brackets + result = [] + for fragment in result_string: + if fragment[0] != "{": + fragment = "{" + fragment + if fragment[len(fragment) - 1] != "}": + fragment = fragment + "}" + result.append(json.loads(fragment)) + + try: # try to defragment when received all fragments + fragment_count = len(result) + announced = int(result[0]["total"]) + + if fragment_count == announced: + reconstructed = "" + sorted_result = [None] * fragment_count # sort fragments.. + unsorted_result = [] + for fragment in result: + unsorted_result.append(fragment) + sorted_result[int(fragment["num"])] = fragment + + for fragment in sorted_result: # reconstruct from fragments + reconstructed = reconstructed + fragment["data"] + + # print "reconstructed", reconstructed + buffer = "" # empty buffer + done = True + print("reconstructed message from", len(result), "fragments") + # print reconstructed + return reconstructed + except Exception as e: + print("not possible to defragment:", buffer) + print(e) + except Exception as e: + print("defrag_error:", buffer) + print(e) + pass + except Exception: + # print "network-error(?):", e + pass + return data + + +def send_service_response(response): # send response to rosbridge + tcp_socket.send(response) + + +def list_of_fragments(full_message, fragment_size): # create fragment messages for a huge message + message_id = randint(0, 64000) # generate random message id + fragments = [] # generate list of data fragments + cursor = 0 + while cursor < len(full_message): + fragment_begin = cursor + if len(full_message) < cursor + fragment_size: + fragment_end = len(full_message) + cursor = len(full_message) + else: + fragment_end = cursor + fragment_size + cursor += fragment_size + fragment = full_message[fragment_begin:fragment_end] + fragments.append(fragment) + + fragmented_messages_list = [] # generate list of fragmented messages (including headers) + if len(fragments) > 1: + for count, fragment in enumerate(fragments): # iterate through list and have index counter + fragmented_message_object = { + "op": "fragment", # create Python-object for each fragment message + "id": str(message_id), + "data": str(fragment), + "num": count, + "total": len(fragments), + } + fragmented_message = json.dumps( + fragmented_message_object + ) # create JSON-object from python-object for each fragment message + fragmented_messages_list.append( + fragmented_message + ) # append JSON-object to list of fragmented messages + else: # if only 1 fragment --> do not send as fragment, but as service_response + fragmented_messages_list.append(str(fragment)) + return fragmented_messages_list # return list of 'ready-to-send' fragmented messages + + +# ##################### helper functions end ################################### + + +# ##################### script begin ########################################### +# should not need to be changed (but could be improved ) # +# ############################################################################## + +tcp_socket = connect_tcp_socket() # open tcp_socket +advertise_service() # advertise service in ROS (via rosbridge) +print("service provider started and waiting for requests") + +try: # allows to catch KeyboardInterrupt + while True: # loop forever (or until ctrl-c is pressed) + data = None + try: # allows to catch any Exception (network, json, ..) + data = wait_for_service_request() # receive request from rosbridge + if data == "": # exit on empty string + break + elif data: # received service_request (or at least some data..) + response = calculate_service_response(data) # generate service_response + + print("response calculated, now splitting into fragments..") + fragment_list = list_of_fragments( + response, send_fragment_size + ) # generate fragments to send to rosbridge + + print("sending", len(fragment_list), "messages as response") + for fragment in fragment_list: + # print "sending:" ,fragment + send_service_response( + fragment + ) # send service_response to rosbridge (or fragments; just send any list entry) + time.sleep( + send_fragment_delay + ) # (not needed if using patched rosbridge protocol.py) + except Exception as e: + print(e) + pass +except KeyboardInterrupt: + try: + unadvertise_service() # unadvertise service + tcp_socket.close() # close tcp_socket + except Exception as e: + print(e) + print('non-ros_service_server stopped because user pressed "Ctrl-C"') diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_multi_publisher.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_multi_publisher.py new file mode 100755 index 000000000..aad200196 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_multi_publisher.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +import unittest +from time import sleep + +import rospy +import rostest +from rosbridge_library.internal import ros_loader +from rosbridge_library.internal.message_conversion import FieldTypeMismatchException +from rosbridge_library.internal.publishers import MultiPublisher +from rosbridge_library.internal.topics import TypeConflictException + + +class TestMultiPublisher(unittest.TestCase): + def setUp(self): + rospy.init_node("test_multi_publisher") + + def is_topic_published(self, topicname): + return topicname in dict(rospy.get_published_topics()).keys() + + def test_register_multipublisher(self): + """Register a publisher on a clean topic with a good msg type""" + topic = "/test_register_multipublisher" + msg_type = "std_msgs/String" + + self.assertFalse(self.is_topic_published(topic)) + _ = MultiPublisher(topic, msg_type) + self.assertTrue(self.is_topic_published(topic)) + + def test_unregister_multipublisher(self): + """Register and unregister a publisher on a clean topic with a good msg type""" + topic = "/test_unregister_multipublisher" + msg_type = "std_msgs/String" + + self.assertFalse(self.is_topic_published(topic)) + multipublisher = MultiPublisher(topic, msg_type) + self.assertTrue(self.is_topic_published(topic)) + multipublisher.unregister() + self.assertFalse(self.is_topic_published(topic)) + + def test_register_client(self): + """Adds a publisher then removes it.""" + topic = "/test_register_client" + msg_type = "std_msgs/String" + client_id = "client1" + + p = MultiPublisher(topic, msg_type) + self.assertFalse(p.has_clients()) + + p.register_client(client_id) + self.assertTrue(p.has_clients()) + + p.unregister_client(client_id) + self.assertFalse(p.has_clients()) + + def test_register_multiple_clients(self): + """Adds multiple publishers then removes them.""" + topic = "/test_register_multiple_clients" + msg_type = "std_msgs/String" + + p = MultiPublisher(topic, msg_type) + self.assertFalse(p.has_clients()) + + for i in range(1000): + p.register_client("client%d" % i) + self.assertTrue(p.has_clients()) + + for i in range(1000): + self.assertTrue(p.has_clients()) + p.unregister_client("client%d" % i) + + self.assertFalse(p.has_clients()) + + def test_verify_type(self): + topic = "/test_verify_type" + msg_type = "std_msgs/String" + othertypes = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] + + p = MultiPublisher(topic, msg_type) + p.verify_type(msg_type) + for othertype in othertypes: + self.assertRaises(TypeConflictException, p.verify_type, othertype) + + def test_publish(self): + """Make sure that publishing works""" + topic = "/test_publish" + msg_type = "std_msgs/String" + msg = {"data": "why halo thar"} + + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + rospy.Subscriber(topic, ros_loader.get_message_class(msg_type), cb) + p = MultiPublisher(topic, msg_type) + p.publish(msg) + + sleep(0.5) + + self.assertEqual(received["msg"].data, msg["data"]) + + def test_bad_publish(self): + """Make sure that bad publishing fails""" + topic = "/test_publish" + msg_type = "std_msgs/String" + msg = {"data": 3} + + p = MultiPublisher(topic, msg_type) + self.assertRaises(FieldTypeMismatchException, p.publish, msg) + + +PKG = "rosbridge_library" +NAME = "test_multi_publisher" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestMultiPublisher) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_multi_unregistering.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_multi_unregistering.py new file mode 100755 index 000000000..896b1bf68 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_multi_unregistering.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +import unittest +from time import sleep + +import rospy +import rostest +from rosbridge_library.internal import ros_loader +from rosbridge_library.internal.publishers import MultiPublisher + + +class TestMultiUnregistering(unittest.TestCase): + def setUp(self): + rospy.init_node("test_multi_unregistering") + + def test_publish_once(self): + """Make sure that publishing works""" + topic = "/test_publish_once" + msg_type = "std_msgs/String" + msg = {"data": "why halo thar"} + + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + rospy.Subscriber(topic, ros_loader.get_message_class(msg_type), cb) + p = MultiPublisher(topic, msg_type) + p.publish(msg) + + sleep(1) + + self.assertEqual(received["msg"].data, msg["data"]) + + def test_publish_twice(self): + """Make sure that publishing works""" + topic = "/test_publish_twice" + msg_type = "std_msgs/String" + msg = {"data": "why halo thar"} + + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + rospy.Subscriber(topic, ros_loader.get_message_class(msg_type), cb) + p = MultiPublisher(topic, msg_type) + p.publish(msg) + + sleep(1) + + self.assertEqual(received["msg"].data, msg["data"]) + + p.unregister() + # The publisher went away at time T. Here's the timeline of the events: + # T+1 seconds - the subscriber will retry to reconnect - fail + # T+3 seconds - the subscriber will retry to reconnect - fail + # T+5 seconds - publish msg -> it's gone + # T+7 seconds - the subscriber will retry to reconnect - success + # T+8 seconds - publish msg -> OK + # T+11 seconds - we receive the message. Looks like a bug in reconnection... + # https://github.com/ros/ros_comm/blob/indigo-devel/clients/rospy/src/rospy/impl/tcpros_base.py#L733 + # That line should probably be indented. + sleep(5) + + received["msg"] = None + self.assertIsNone(received["msg"]) + p = MultiPublisher(topic, msg_type) + p.publish(msg) + + self.assertIsNone(received["msg"]) + + sleep(3) + p.publish(msg) + sleep(2) + # Next two lines should be removed when this is fixed: + # https://github.com/ros/ros_comm/blob/indigo-devel/clients/rospy/src/rospy/impl/tcpros_base.py#L733 + self.assertIsNone(received["msg"]) + sleep(3) + self.assertEqual(received["msg"].data, msg["data"]) + + +PKG = "rosbridge_library" +NAME = "test_multi_unregistering" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestMultiUnregistering) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_publisher_manager.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_publisher_manager.py new file mode 100755 index 000000000..f0a739957 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/publishers/test_publisher_manager.py @@ -0,0 +1,216 @@ +#!/usr/bin/env python +import unittest +from time import sleep + +import rospy +import rostest +from rosbridge_library.internal.message_conversion import FieldTypeMismatchException +from rosbridge_library.internal.publishers import manager +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) +from std_msgs.msg import String + + +class TestPublisherManager(unittest.TestCase): + def setUp(self): + rospy.init_node("test_publisher_manager") + manager.unregister_timeout = 1.0 + + def is_topic_published(self, topicname): + return topicname in dict(rospy.get_published_topics()).keys() + + def test_register_publisher(self): + """Register a publisher on a clean topic with a good msg type""" + topic = "/test_register_publisher" + msg_type = "std_msgs/String" + client = "client_test_register_publisher" + + self.assertFalse(topic in manager._publishers) + self.assertFalse(self.is_topic_published(topic)) + manager.register(client, topic, msg_type) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + + manager.unregister(client, topic) + self.assertTrue(topic in manager.unregister_timers) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + sleep(manager.unregister_timeout * 1.1) + self.assertFalse(topic in manager._publishers) + self.assertFalse(self.is_topic_published(topic)) + self.assertFalse(topic in manager.unregister_timers) + + def test_register_publisher_multiclient(self): + topic = "/test_register_publisher_multiclient" + msg_type = "std_msgs/String" + client1 = "client_test_register_publisher_1" + client2 = "client_test_register_publisher_2" + + self.assertFalse(topic in manager._publishers) + self.assertFalse(self.is_topic_published(topic)) + manager.register(client1, topic, msg_type) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + manager.register(client2, topic, msg_type) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + manager.unregister(client1, topic) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + manager.unregister(client2, topic) + self.assertTrue(topic in manager.unregister_timers) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + sleep(manager.unregister_timeout * 1.1) + self.assertFalse(topic in manager._publishers) + self.assertFalse(self.is_topic_published(topic)) + self.assertFalse(topic in manager.unregister_timers) + + def test_register_publisher_conflicting_types(self): + topic = "/test_register_publisher_conflicting_types" + msg_type = "std_msgs/String" + msg_type_bad = "std_msgs/Int32" + client = "client_test_register_publisher_conflicting_types" + + self.assertFalse(topic in manager._publishers) + self.assertFalse(self.is_topic_published(topic)) + manager.register(client, topic, msg_type) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + + self.assertRaises(TypeConflictException, manager.register, "client2", topic, msg_type_bad) + + def test_register_multiple_publishers(self): + topic1 = "/test_register_multiple_publishers1" + topic2 = "/test_register_multiple_publishers2" + msg_type = "std_msgs/String" + client = "client_test_register_multiple_publishers" + + self.assertFalse(topic1 in manager._publishers) + self.assertFalse(topic2 in manager._publishers) + self.assertFalse(self.is_topic_published(topic1)) + self.assertFalse(self.is_topic_published(topic2)) + manager.register(client, topic1, msg_type) + self.assertTrue(topic1 in manager._publishers) + self.assertTrue(self.is_topic_published(topic1)) + self.assertFalse(topic2 in manager._publishers) + self.assertFalse(self.is_topic_published(topic2)) + manager.register(client, topic2, msg_type) + self.assertTrue(topic1 in manager._publishers) + self.assertTrue(self.is_topic_published(topic1)) + self.assertTrue(topic2 in manager._publishers) + self.assertTrue(self.is_topic_published(topic2)) + + manager.unregister(client, topic1) + self.assertTrue(self.is_topic_published(topic1)) + self.assertTrue(topic1 in manager.unregister_timers) + self.assertTrue(topic2 in manager._publishers) + self.assertTrue(self.is_topic_published(topic2)) + + manager.unregister(client, topic2) + self.assertTrue(topic2 in manager.unregister_timers) + self.assertTrue(self.is_topic_published(topic2)) + sleep(manager.unregister_timeout * 1.1) + self.assertFalse(topic1 in manager._publishers) + self.assertFalse(self.is_topic_published(topic1)) + self.assertFalse(topic2 in manager._publishers) + self.assertFalse(self.is_topic_published(topic2)) + self.assertFalse(topic1 in manager.unregister_timers) + self.assertFalse(topic2 in manager.unregister_timers) + + def test_register_no_msgtype(self): + topic = "/test_register_no_msgtype" + client = "client_test_register_no_msgtype" + + self.assertFalse(topic in manager._publishers) + self.assertFalse(self.is_topic_published(topic)) + self.assertRaises(TopicNotEstablishedException, manager.register, client, topic) + + def test_register_infer_topictype(self): + topic = "/test_register_infer_topictype" + client = "client_test_register_infer_topictype" + + self.assertFalse(self.is_topic_published(topic)) + + rospy.Publisher(topic, String) + + self.assertTrue(self.is_topic_published(topic)) + self.assertFalse(topic in manager._publishers) + manager.register(client, topic) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + + manager.unregister(client, topic) + self.assertTrue(topic in manager.unregister_timers) + self.assertTrue(self.is_topic_published(topic)) + + def test_register_multiple_notopictype(self): + topic = "/test_register_multiple_notopictype" + msg_type = "std_msgs/String" + client1 = "client_test_register_multiple_notopictype_1" + client2 = "client_test_register_multiple_notopictype_2" + + self.assertFalse(topic in manager._publishers) + self.assertFalse(topic in manager.unregister_timers) + self.assertFalse(self.is_topic_published(topic)) + manager.register(client1, topic, msg_type) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + manager.register(client2, topic) + self.assertTrue(topic in manager._publishers) + self.assertTrue(self.is_topic_published(topic)) + manager.unregister(client1, topic) + self.assertTrue(topic in manager._publishers) + self.assertTrue(topic in manager.unregister_timers) + self.assertTrue(self.is_topic_published(topic)) + manager.unregister(client2, topic) + self.assertTrue(topic in manager.unregister_timers) + self.assertTrue(topic in manager._publishers) + sleep(manager.unregister_timeout * 1.1) + self.assertFalse(topic in manager._publishers) + self.assertFalse(topic in manager.unregister_timers) + self.assertFalse(self.is_topic_published(topic)) + + def test_publish_not_registered(self): + topic = "/test_publish_not_registered" + msg = {"data": "test publish not registered"} + client = "client_test_publish_not_registered" + + self.assertFalse(topic in manager._publishers) + self.assertFalse(self.is_topic_published(topic)) + self.assertRaises(TopicNotEstablishedException, manager.publish, client, topic, msg) + + def test_publisher_manager_publish(self): + """Make sure that publishing works""" + topic = "/test_publisher_manager_publish" + msg = {"data": "test publisher manager publish"} + client = "client_test_publisher_manager_publish" + + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + rospy.Subscriber(topic, String, cb) + manager.publish(client, topic, msg) + sleep(0.5) + + self.assertEqual(received["msg"].data, msg["data"]) + + def test_publisher_manager_bad_publish(self): + """Make sure that bad publishing fails""" + topic = "/test_publisher_manager_bad_publish" + client = "client_test_publisher_manager_bad_publish" + msg_type = "std_msgs/String" + msg = {"data": 3} + + manager.register(client, topic, msg_type) + self.assertRaises(FieldTypeMismatchException, manager.publish, client, topic, msg) + + +PKG = "rosbridge_library" +NAME = "test_publisher_manager" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestPublisherManager) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/__init__.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py new file mode 100755 index 000000000..915b92f93 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_multi_subscriber.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python +import unittest +from time import sleep + +import rospy +import rostest +from rosbridge_library.internal.subscribers import MultiSubscriber +from rosbridge_library.internal.topics import TypeConflictException +from rosgraph import Master +from std_msgs.msg import Int32, String + + +class TestMultiSubscriber(unittest.TestCase): + def setUp(self): + rospy.init_node("test_multi_subscriber") + + def is_topic_published(self, topicname): + return topicname in dict(rospy.get_published_topics()).keys() + + def is_topic_subscribed(self, topicname): + return topicname in dict(Master("test_multi_subscriber").getSystemState()[1]) + + def test_register_multisubscriber(self): + """Register a subscriber on a clean topic with a good msg type""" + topic = "/test_register_multisubscriber" + msg_type = "std_msgs/String" + + self.assertFalse(self.is_topic_subscribed(topic)) + MultiSubscriber(topic, msg_type) + self.assertTrue(self.is_topic_subscribed(topic)) + + def test_unregister_multisubscriber(self): + """Register and unregister a subscriber on a clean topic with a good msg type""" + topic = "/test_unregister_multisubscriber" + msg_type = "std_msgs/String" + + self.assertFalse(self.is_topic_subscribed(topic)) + multi = MultiSubscriber(topic, msg_type) + self.assertTrue(self.is_topic_subscribed(topic)) + multi.unregister() + self.assertFalse(self.is_topic_subscribed(topic)) + + def test_verify_type(self): + topic = "/test_verify_type" + msg_type = "std_msgs/String" + othertypes = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] + + s = MultiSubscriber(topic, msg_type) + s.verify_type(msg_type) + for othertype in othertypes: + self.assertRaises(TypeConflictException, s.verify_type, othertype) + + def test_subscribe_unsubscribe(self): + topic = "/test_subscribe_unsubscribe" + msg_type = "std_msgs/String" + client = "client_test_subscribe_unsubscribe" + + self.assertFalse(self.is_topic_subscribed(topic)) + multi = MultiSubscriber(topic, msg_type) + self.assertTrue(self.is_topic_subscribed(topic)) + self.assertFalse(multi.has_subscribers()) + + multi.subscribe(client, None) + self.assertTrue(multi.has_subscribers()) + + multi.unsubscribe(client) + self.assertFalse(multi.has_subscribers()) + + multi.unregister() + self.assertFalse(self.is_topic_subscribed(topic)) + + def test_subscribe_receive_json(self): + topic = "/test_subscribe_receive_json" + msg_type = "std_msgs/String" + client = "client_test_subscribe_receive_json" + + msg = String() + msg.data = "dsajfadsufasdjf" + + pub = rospy.Publisher(topic, String) + multi = MultiSubscriber(topic, msg_type) + + received = {"msg": None} + + def cb(msg): + received["msg"] = msg.get_json_values() + + multi.subscribe(client, cb) + sleep(0.5) + pub.publish(msg) + sleep(0.5) + self.assertEqual(msg.data, received["msg"]["data"]) + + def test_subscribe_receive_json_multiple(self): + topic = "/test_subscribe_receive_json_multiple" + msg_type = "std_msgs/Int32" + client = "client_test_subscribe_receive_json_multiple" + + numbers = list(range(100)) + + pub = rospy.Publisher(topic, Int32) + multi = MultiSubscriber(topic, msg_type) + + received = {"msgs": []} + + def cb(msg): + received["msgs"].append(msg.get_json_values()["data"]) + + multi.subscribe(client, cb) + sleep(0.5) + for x in numbers: + msg = Int32() + msg.data = x + pub.publish(msg) + sleep(0.5) + self.assertEqual(numbers, received["msgs"]) + + def test_unsubscribe_does_not_receive_further_msgs(self): + topic = "/test_unsubscribe_does_not_receive_further_msgs" + msg_type = "std_msgs/String" + client = "client_test_unsubscribe_does_not_receive_further_msgs" + + msg = String() + msg.data = "dsajfadsufasdjf" + + pub = rospy.Publisher(topic, String) + multi = MultiSubscriber(topic, msg_type) + + received = {"count": 0} + + def cb(msg): + received["count"] = received["count"] + 1 + + multi.subscribe(client, cb) + sleep(0.5) + pub.publish(msg) + sleep(0.5) + self.assertEqual(received["count"], 1) + multi.unsubscribe(client) + sleep(0.5) + pub.publish(msg) + sleep(0.5) + self.assertEqual(received["count"], 1) + + def test_multiple_subscribers(self): + topic = "/test_subscribe_receive_json" + msg_type = "std_msgs/String" + client1 = "client_test_subscribe_receive_json_1" + client2 = "client_test_subscribe_receive_json_2" + + msg = String() + msg.data = "dsajfadsufasdjf" + + pub = rospy.Publisher(topic, String) + multi = MultiSubscriber(topic, msg_type) + + received = {"msg1": None, "msg2": None} + + def cb1(msg): + received["msg1"] = msg.get_json_values() + + def cb2(msg): + received["msg2"] = msg.get_json_values() + + multi.subscribe(client1, cb1) + multi.subscribe(client2, cb2) + sleep(0.5) + pub.publish(msg) + sleep(0.5) + self.assertEqual(msg.data, received["msg1"]["data"]) + self.assertEqual(msg.data, received["msg2"]["data"]) + + +PKG = "rosbridge_library" +NAME = "test_multi_subscriber" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestMultiSubscriber) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py new file mode 100755 index 000000000..9e0f82769 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_subscriber_manager.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python +import unittest +from time import sleep + +import rospy +import rostest +from rosbridge_library.internal.subscribers import manager +from rosbridge_library.internal.topics import ( + TopicNotEstablishedException, + TypeConflictException, +) +from rosgraph import Master +from std_msgs.msg import String + + +class TestSubscriberManager(unittest.TestCase): + def setUp(self): + rospy.init_node("test_subscriber_manager") + + def is_topic_published(self, topicname): + return topicname in dict(rospy.get_published_topics()).keys() + + def is_topic_subscribed(self, topicname): + return topicname in dict(Master("test_subscriber_manager").getSystemState()[1]) + + def test_subscribe(self): + """Register a publisher on a clean topic with a good msg type""" + topic = "/test_subscribe" + msg_type = "std_msgs/String" + client = "client_test_subscribe" + + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + manager.subscribe(client, topic, None, msg_type) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + + manager.unsubscribe(client, topic) + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + + def test_register_subscriber_multiclient(self): + topic = "/test_register_subscriber_multiclient" + msg_type = "std_msgs/String" + client1 = "client_test_register_subscriber_multiclient_1" + client2 = "client_test_register_subscriber_multiclient_2" + + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + manager.subscribe(client1, topic, None, msg_type) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + manager.subscribe(client2, topic, None, msg_type) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + manager.unsubscribe(client1, topic) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + manager.unsubscribe(client2, topic) + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + + def test_register_publisher_conflicting_types(self): + topic = "/test_register_publisher_conflicting_types" + msg_type = "std_msgs/String" + msg_type_bad = "std_msgs/Int32" + client = "client_test_register_publisher_conflicting_types" + + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + manager.subscribe(client, topic, None, msg_type) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + + self.assertRaises( + TypeConflictException, + manager.subscribe, + "client2", + topic, + None, + msg_type_bad, + ) + + def test_register_multiple_publishers(self): + topic1 = "/test_register_multiple_publishers1" + topic2 = "/test_register_multiple_publishers2" + msg_type = "std_msgs/String" + client = "client_test_register_multiple_publishers" + + self.assertFalse(topic1 in manager._subscribers) + self.assertFalse(topic2 in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic1)) + self.assertFalse(self.is_topic_subscribed(topic2)) + manager.subscribe(client, topic1, None, msg_type) + self.assertTrue(topic1 in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic1)) + self.assertFalse(topic2 in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic2)) + manager.subscribe(client, topic2, None, msg_type) + self.assertTrue(topic1 in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic1)) + self.assertTrue(topic2 in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic2)) + + manager.unsubscribe(client, topic1) + self.assertFalse(topic1 in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic1)) + self.assertTrue(topic2 in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic2)) + + manager.unsubscribe(client, topic2) + self.assertFalse(topic1 in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic1)) + self.assertFalse(topic2 in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic2)) + + def test_register_no_msgtype(self): + topic = "/test_register_no_msgtype" + client = "client_test_register_no_msgtype" + + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + self.assertRaises(TopicNotEstablishedException, manager.subscribe, client, topic, None) + + def test_register_infer_topictype(self): + topic = "/test_register_infer_topictype" + client = "client_test_register_infer_topictype" + + self.assertFalse(self.is_topic_subscribed(topic)) + + rospy.Subscriber(topic, String, None) + + self.assertTrue(self.is_topic_subscribed(topic)) + self.assertFalse(topic in manager._subscribers) + manager.subscribe(client, topic, None) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + + manager.unsubscribe(client, topic) + self.assertFalse(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + + def test_register_multiple_notopictype(self): + topic = "/test_register_multiple_notopictype" + msg_type = "std_msgs/String" + client1 = "client_test_register_multiple_notopictype_1" + client2 = "client_test_register_multiple_notopictype_2" + + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + manager.subscribe(client1, topic, None, msg_type) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + manager.subscribe(client2, topic, None) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + manager.unsubscribe(client1, topic) + self.assertTrue(topic in manager._subscribers) + self.assertTrue(self.is_topic_subscribed(topic)) + manager.unsubscribe(client2, topic) + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + + def test_subscribe_not_registered(self): + topic = "/test_subscribe_not_registered" + client = "client_test_subscribe_not_registered" + + self.assertFalse(topic in manager._subscribers) + self.assertFalse(self.is_topic_subscribed(topic)) + self.assertRaises(TopicNotEstablishedException, manager.subscribe, client, topic, None) + + def test_publisher_manager_publish(self): + topic = "/test_publisher_manager_publish" + msg_type = "std_msgs/String" + client = "client_test_publisher_manager_publish" + + msg = String() + msg.data = "dsajfadsufasdjf" + + pub = rospy.Publisher(topic, String) + received = {"msg": None} + + def cb(msg): + received["msg"] = msg.get_json_values() + + manager.subscribe(client, topic, cb, msg_type) + sleep(0.5) + pub.publish(msg) + sleep(0.5) + self.assertEqual(msg.data, received["msg"]["data"]) + + +PKG = "rosbridge_library" +NAME = "test_subscriber_manager" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestSubscriberManager) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py new file mode 100755 index 000000000..40fad012c --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/subscribers/test_subscription_modifiers.py @@ -0,0 +1,375 @@ +#!/usr/bin/env python +import time +import unittest + +import rospy +import rostest +from rosbridge_library.internal import subscription_modifiers as subscribe + + +class TestMessageHandlers(unittest.TestCase): + def setUp(self): + rospy.init_node("test_message_handlers") + + def dummy_cb(self, msg): + pass + + def test_default_message_handler(self): + handler = subscribe.MessageHandler(None, self.dummy_cb) + self.help_test_default(handler) + + def test_throttle_message_handler(self): + handler = subscribe.ThrottleMessageHandler(subscribe.MessageHandler(None, self.dummy_cb)) + self.help_test_throttle(handler, 50) + + def test_queue_message_handler_passes_msgs(self): + handler = subscribe.QueueMessageHandler(subscribe.MessageHandler(None, self.dummy_cb)) + self.help_test_queue(handler, 1000) + handler.finish() + + def test_queue_message_handler_stops(self): + received = {"msgs": []} + + def cb(msg): + received["msgs"].append(msg) + + handler = subscribe.QueueMessageHandler(subscribe.MessageHandler(None, cb)) + + self.assertTrue(handler.is_alive()) + + handler.finish() + + self.assertFalse(handler.is_alive()) + + def test_queue_message_handler_queue(self): + received = {"msgs": []} + + def cb(msg): + received["msgs"].append(msg) + + msgs = range(1000) + + handler = subscribe.MessageHandler(None, cb) + + handler = handler.set_throttle_rate(10000) + handler = handler.set_queue_length(10) + self.assertIsInstance(handler, subscribe.QueueMessageHandler) + + # 'hello' is handled immediately + handler.handle_message("hello") + time.sleep(0.02) + # queue is now empty, but throttling is in effect + # no messages will be handled in the next 10 seconds + + # these will fill up the queue, with newer values displacing old ones + # nothing gets sent because the throttle rate + for x in msgs: + handler.handle_message(x) + + handler = handler.set_throttle_rate(0) + + time.sleep(0.1) + + try: + self.assertEqual(["hello"] + list(range(990, 1000)), received["msgs"]) + finally: + handler.finish() + + def test_queue_message_handler_dropping(self): + received = {"msgs": []} + + def cb(msg): + received["msgs"].append(msg) + time.sleep(1) + + queue_length = 5 + msgs = range(queue_length * 5) + + handler = subscribe.MessageHandler(None, cb) + + handler = handler.set_queue_length(queue_length) + self.assertIsInstance(handler, subscribe.QueueMessageHandler) + + # send all messages at once. + # only the first and the last queue_length should get through, + # because the callbacks are blocked. + for x in msgs: + handler.handle_message(x) + # yield the thread so the first callback can append, + # otherwise the first handled value is non-deterministic. + time.sleep(0) + + # wait long enough for all the callbacks, and then some. + time.sleep(queue_length + 3) + + try: + self.assertEqual([msgs[0]] + msgs[-queue_length:], received["msgs"]) + except: # noqa: E722 # Will finish and raise + handler.finish() + raise + + handler.finish() + + def test_queue_message_handler_rate(self): + handler = subscribe.MessageHandler(None, self.dummy_cb) + self.help_test_queue_rate(handler, 50, 10) + handler.finish() + + # Helper methods for each of the three Handler types, plus one for Queue+Rate. + # Used in standalone testing as well as the test_transition_functionality test + def help_test_default(self, handler): + handler = handler.set_queue_length(0) + handler = handler.set_throttle_rate(0) + self.assertIsInstance(handler, subscribe.MessageHandler) + + msg = "test_default_message_handler" + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + handler.publish = cb + + self.assertTrue(handler.time_remaining() == 0) + t1 = time.time() + handler.handle_message(msg) + t2 = time.time() + + self.assertEqual(received["msg"], msg) + self.assertLessEqual(t1, handler.last_publish) + self.assertLessEqual(handler.last_publish, t2) + self.assertEqual(handler.time_remaining(), 0) + + received = {"msgs": []} + + def cb(msg): + received["msgs"].append(msg) + + handler.publish = cb + xs = list(range(10000)) + for x in xs: + handler.handle_message(x) + + self.assertEqual(received["msgs"], xs) + return handler + + def help_test_throttle(self, handler, throttle_rate): + handler = handler.set_queue_length(0) + handler = handler.set_throttle_rate(throttle_rate) + self.assertIsInstance(handler, subscribe.ThrottleMessageHandler) + + msg = "test_throttle_message_handler" + + # First, try with a single message + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + handler.publish = cb + + # ensure the handler doesn't swallow this message + time.sleep(2.0 * handler.throttle_rate) + handler.handle_message(msg) + self.assertEqual(received["msg"], msg) + + # sleep to make sure the handler sends right away for the second part + time.sleep(2.0 * handler.throttle_rate) + + received = {"msgs": []} + + def cb(msg): + received["msgs"].append(msg) + + handler.publish = cb + x = 0 + time_padding = handler.throttle_rate / 4.0 + for i in range(1, 10): + # We guarantee that in the while loop below only the first message is handled + # All subsequent messages (within throttling window - time_padding ) are dropped + # Time padding is a test-only hack around race condition when time.time() - fin is within + # the throttling window, but handler.handle_message(x) gets a later timestamp that is outside. + time.sleep(2.0 * time_padding) + fin = time.time() + throttle_rate / 1000.0 - time_padding + while time.time() < fin: + handler.handle_message(x) + x = x + 1 + self.assertEqual(len(received["msgs"]), i) + return handler + + def help_test_queue(self, handler, queue_length): + handler = handler.set_queue_length(queue_length) + self.assertIsInstance(handler, subscribe.QueueMessageHandler) + + received = {"msgs": []} + + def cb(msg): + received["msgs"].append(msg) + + handler.publish = cb + + msgs = list(range(queue_length)) + for x in msgs: + handler.handle_message(x) + + time.sleep(0.1) + + self.assertEqual(msgs, received["msgs"]) + return handler + + def help_test_queue_rate(self, handler, throttle_rate, queue_length): + handler = handler.set_throttle_rate(throttle_rate) + handler = handler.set_queue_length(queue_length) + self.assertIsInstance(handler, subscribe.QueueMessageHandler) + + received = {"msg": None} + + def cb(msg): + received["msg"] = msg + + handler.publish = cb + + throttle_rate_sec = throttle_rate / 1000.0 + + # ensure previous tests' last sent time is long enough ago + time.sleep(throttle_rate_sec) + for x in range(queue_length): + handler.handle_message(x) + + time.sleep(throttle_rate_sec / 2.0) + + try: + for x in range(10): + self.assertEqual(x, received["msg"]) + time.sleep(throttle_rate_sec) + except: # noqa: E722 # Will finish and raise + handler.finish() + raise + + return handler + + # Test that each transition works and is stable + def test_transitions(self): + # MessageHandler.transition is stable + handler = subscribe.MessageHandler(None, self.dummy_cb) + next_handler = handler.transition() + self.assertEqual(handler, next_handler) + + # Going from MessageHandler to ThrottleMessageHandler... + handler = subscribe.MessageHandler(None, self.dummy_cb) + next_handler = handler.set_throttle_rate(100) + self.assertIsInstance(next_handler, subscribe.ThrottleMessageHandler) + handler = next_handler + # Testing transition returns another ThrottleMessageHandler + next_handler = handler.transition() + self.assertEqual(handler, next_handler) + # And finally going back to MessageHandler + next_handler = handler.set_throttle_rate(0) + self.assertIsInstance(next_handler, subscribe.MessageHandler) + + # Same for QueueMessageHandler + handler = subscribe.MessageHandler(None, self.dummy_cb) + next_handler = handler.set_queue_length(100) + self.assertIsInstance(next_handler, subscribe.QueueMessageHandler) + handler = next_handler + next_handler = handler.transition() + self.assertEqual(handler, next_handler) + next_handler = handler.set_queue_length(0) + self.assertIsInstance(next_handler, subscribe.MessageHandler) + + # Checking a QueueMessageHandler with rate limit can be generated both ways + handler = subscribe.MessageHandler(None, self.dummy_cb) + next_handler = handler.set_queue_length(100).set_throttle_rate(100) + self.assertIsInstance(next_handler, subscribe.QueueMessageHandler) + next_handler.finish() + next_handler = handler.set_throttle_rate(100).set_queue_length(100) + self.assertIsInstance(next_handler, subscribe.QueueMessageHandler) + next_handler.finish() + handler = next_handler + next_handler = handler.transition() + self.assertEqual(handler, next_handler) + # Check both steps on the way back to plain MessageHandler + next_handler = handler.set_throttle_rate(0) + self.assertIsInstance(next_handler, subscribe.QueueMessageHandler) + next_handler = handler.set_queue_length(0) + self.assertIsInstance(next_handler, subscribe.MessageHandler) + + def test_transition_functionality(self): + # Test individually + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_queue(handler, 10) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_throttle(handler, 50) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_default(handler) + handler.finish() + + # Test combinations + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_queue(handler, 10) + handler = self.help_test_throttle(handler, 50) + handler = self.help_test_default(handler) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_queue(handler, 10) + handler = self.help_test_default(handler) + handler = self.help_test_throttle(handler, 50) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_throttle(handler, 50) + handler = self.help_test_queue_rate(handler, 50, 10) + handler = self.help_test_default(handler) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_throttle(handler, 50) + handler = self.help_test_default(handler) + handler = self.help_test_queue_rate(handler, 50, 10) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_default(handler) + handler = self.help_test_throttle(handler, 50) + handler = self.help_test_queue_rate(handler, 50, 10) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_default(handler) + handler = self.help_test_queue(handler, 10) + handler = self.help_test_throttle(handler, 50) + handler.finish() + + # Test duplicates + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_queue_rate(handler, 50, 10) + handler = self.help_test_queue_rate(handler, 100, 10) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_throttle(handler, 50) + handler = self.help_test_throttle(handler, 100) + handler.finish() + + handler = subscribe.MessageHandler(None, None) + handler = self.help_test_default(handler) + handler = self.help_test_default(handler) + handler.finish() + + +# handler = self.help_test_throttle(handler, 50) +# handler = self.help_test_default(handler) +# handler = self.help_test_throttle(handler, 50) +# handler = self.help_test_default(handler) +# handler = self.help_test_throttle(handler, 50) + + +PKG = "rosbridge_library" +NAME = "test_message_handlers" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestMessageHandlers) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_cbor_conversion.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_cbor_conversion.py new file mode 100755 index 000000000..8a5f0e4f1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_cbor_conversion.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python3 +import struct +import unittest + +import rostest +from rosbridge_library.internal.cbor_conversion import ( + TAGGED_ARRAY_FORMATS, + extract_cbor_values, +) + +try: + from cbor import Tag +except ImportError: + from rosbridge_library.util.cbor import Tag + +from std_msgs.msg import ( + Bool, + Duration, + Float32, + Float32MultiArray, + Float64, + Float64MultiArray, + Int8, + Int8MultiArray, + Int16, + Int16MultiArray, + Int32, + Int32MultiArray, + Int64, + Int64MultiArray, + MultiArrayDimension, + MultiArrayLayout, + String, + Time, + UInt8, + UInt8MultiArray, + UInt16, + UInt16MultiArray, + UInt32, + UInt32MultiArray, + UInt64, + UInt64MultiArray, +) + + +class TestCBORConversion(unittest.TestCase): + def test_string(self): + msg = String(data="foo") + extracted = extract_cbor_values(msg) + + self.assertEqual(extracted["data"], msg.data) + self.assertEqual(type(extracted["data"]), str) + + def test_bool(self): + for val in [True, False]: + msg = Bool(data=val) + extracted = extract_cbor_values(msg) + + self.assertEqual(extracted["data"], msg.data, f"val={val}") + self.assertEqual(type(extracted["data"]), bool, f"val={val}") + + def test_numbers(self): + for msg_type in [Int8, Int16, Int32, Int64]: + msg = msg_type(data=-5) + extracted = extract_cbor_values(msg) + + self.assertEqual(extracted["data"], msg.data, f"type={msg_type}") + self.assertEqual(type(extracted["data"]), int, f"type={msg_type}") + + for msg_type in [UInt8, UInt16, UInt32, UInt64]: + msg = msg_type(data=5) + extracted = extract_cbor_values(msg) + + self.assertEqual(extracted["data"], msg.data, f"type={msg_type}") + self.assertEqual(type(extracted["data"]), int, f"type={msg_type}") + + for msg_type in [Float32, Float64]: + msg = msg_type(data=2.3) + extracted = extract_cbor_values(msg) + + self.assertEqual(extracted["data"], msg.data, f"type={msg_type}") + self.assertEqual(type(extracted["data"]), float, f"type={msg_type}") + + def test_time(self): + for msg_type in [Time, Duration]: + msg = msg_type() + extracted = extract_cbor_values(msg) + + self.assertEqual(extracted["data"]["secs"], msg.data.secs, f"type={msg_type}") + self.assertEqual(extracted["data"]["nsecs"], msg.data.nsecs, f"type={msg_type}") + self.assertEqual(type(extracted["data"]["secs"]), int, f"type={msg_type}") + self.assertEqual(type(extracted["data"]["nsecs"]), int, f"type={msg_type}") + + def test_byte_array(self): + msg = UInt8MultiArray(data=[0, 1, 2]) + extracted = extract_cbor_values(msg) + + data = extracted["data"] + self.assertEqual(type(data), bytes) + for i, val in enumerate(msg.data): + self.assertEqual(data[i], val) + + def test_numeric_array(self): + for msg_type in [ + Int8MultiArray, + Int16MultiArray, + Int32MultiArray, + Int64MultiArray, + UInt16MultiArray, + UInt32MultiArray, + UInt64MultiArray, + Float32MultiArray, + Float64MultiArray, + ]: + msg = msg_type(data=[0, 1, 2]) + extracted = extract_cbor_values(msg) + + tag = extracted["data"] + self.assertEqual(type(tag), Tag, f"type={msg_type}") + self.assertEqual(type(tag.value), bytes, f"type={msg_type}") + + # This is as consistent as the message defs.. + array_type = msg._slot_types[1] + + expected_tag = TAGGED_ARRAY_FORMATS[array_type][0] + self.assertEqual(tag.tag, expected_tag, f"type={msg_type}") + + fmt = TAGGED_ARRAY_FORMATS[array_type][1] + fmt_to_length = fmt.format(len(msg.data)) + unpacked = list(struct.unpack(fmt_to_length, tag.value)) + + self.assertEqual(unpacked, msg.data, f"type={msg_type}") + + def test_nested_messages(self): + msg = UInt8MultiArray( + layout=MultiArrayLayout( + data_offset=5, + dim=[ + MultiArrayDimension( + label="foo", + size=4, + stride=4, + ), + MultiArrayDimension( + label="bar", + size=8, + stride=8, + ), + ], + ) + ) + extracted = extract_cbor_values(msg) + + ex_layout = extracted["layout"] + self.assertEqual(type(ex_layout), dict) + self.assertEqual(ex_layout["data_offset"], msg.layout.data_offset) + self.assertEqual(len(ex_layout["dim"]), len(msg.layout.dim)) + for i, val in enumerate(msg.layout.dim): + self.assertEqual(ex_layout["dim"][i]["label"], val.label) + self.assertEqual(ex_layout["dim"][i]["size"], val.size) + self.assertEqual(ex_layout["dim"][i]["stride"], val.stride) + + def test_unicode_keys(self): + msg = String(data="foo") + extracted = extract_cbor_values(msg) + + keys = extracted.keys() + for key in keys: + self.assertEqual(type(key), str) + + +PKG = "rosbridge_library" +NAME = "test_cbor_conversion" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestCBORConversion) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_compression.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_compression.py new file mode 100755 index 000000000..7e5ebfcfb --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_compression.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +import unittest + +import rospy +import rostest +from rosbridge_library.internal import pngcompression + + +class TestCompression(unittest.TestCase): + def setUp(self): + rospy.init_node("test_compression") + + def test_compress(self): + bytes = list(range(128)) * 10000 + string = str(bytearray(bytes)) + encoded = pngcompression.encode(string) + self.assertNotEqual(string, encoded) + + def test_compress_decompress(self): + bytes = list(range(128)) * 10000 + string = str(bytearray(bytes)) + encoded = pngcompression.encode(string) + self.assertNotEqual(string, encoded) + decoded = pngcompression.decode(encoded) + self.assertEqual(string, decoded) + + +PKG = "rosbridge_library" +NAME = "test_compression" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestCompression) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_message_conversion.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_message_conversion.py new file mode 100755 index 000000000..9ccba4f05 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_message_conversion.py @@ -0,0 +1,318 @@ +#!/usr/bin/env python3 +import unittest +from base64 import standard_b64encode +from json import dumps, loads + +import numpy as np +from rclpy.serialization import deserialize_message, serialize_message +from rosbridge_library.internal import message_conversion as c +from rosbridge_library.internal import ros_loader + + +class TestMessageConversion(unittest.TestCase): + def validate_instance(self, inst1): + """Serializes and deserializes the inst to typecheck and ensure that + instances are correct""" + inst2 = deserialize_message(serialize_message(inst1), type(inst1)) + self.assertEqual(inst1, inst2) + + def msgs_equal(self, msg1, msg2): + if isinstance(msg1, str) and isinstance(msg2, str): + pass + else: + self.assertEqual(type(msg1), type(msg2)) + if type(msg1) in c.list_types: + for x, y in zip(msg1, msg2): + self.msgs_equal(x, y) + elif type(msg1) in c.primitive_types or type(msg1) is str: + self.assertEqual(msg1, msg2) + else: + for x in msg1: + self.assertTrue(x in msg2) + for x in msg2: + self.assertTrue(x in msg1) + for x in msg1: + self.msgs_equal(msg1[x], msg2[x]) + + def do_primitive_test(self, data_value, msgtype): + for msg in [{"data": data_value}, loads(dumps({"data": data_value}))]: + inst = ros_loader.get_message_instance(msgtype) + c.populate_instance(msg, inst) + self.assertEqual(inst.data, data_value) + self.validate_instance(inst) + extracted = c.extract_values(inst) + for msg2 in [extracted, loads(dumps(extracted))]: + self.msgs_equal(msg, msg2) + self.assertEqual(msg["data"], msg2["data"]) + self.assertEqual(msg2["data"], inst.data) + + def do_byte_test(self, data_value, msgtype): + for msg in [{"data": data_value}]: + inst = ros_loader.get_message_instance(msgtype) + c.populate_instance(msg, inst) + self.assertEqual(inst.data, bytes([data_value])) + self.validate_instance(inst) + extracted = c.extract_values(inst) + for msg2 in [extracted, loads(dumps(extracted))]: + self.assertEqual(msg["data"], msg2["data"]) + self.assertEqual(bytes([msg2["data"]]), inst.data) + + def do_test(self, orig_msg, msgtype): + for msg in [orig_msg, loads(dumps(orig_msg))]: + inst = ros_loader.get_message_instance(msgtype) + c.populate_instance(msg, inst) + self.validate_instance(inst) + extracted = c.extract_values(inst) + for msg2 in [extracted, loads(dumps(extracted))]: + self.msgs_equal(msg, msg2) + + def test_int_primitives(self): + # Test raw primitives + for msg in range(-100, 100): + for rostype in ["int8", "int16", "int32", "int64"]: + self.assertEqual(c._to_primitive_inst(msg, rostype, rostype, []), msg) + self.assertEqual(c._to_inst(msg, rostype, rostype), msg) + # Test raw primitives + for msg in range(0, 200): + for rostype in ["uint8", "uint16", "uint32", "uint64"]: + self.assertEqual(c._to_primitive_inst(msg, rostype, rostype, []), msg) + self.assertEqual(c._to_inst(msg, rostype, rostype), msg) + + def test_byte_primitives(self): + # Test raw primitives + for msg in range(0, 200): + for rostype in ["octet"]: + self.assertEqual(c._to_primitive_inst(msg, rostype, rostype, []), bytes([msg])) + self.assertEqual(c._to_inst(msg, rostype, rostype), bytes([msg])) + + def test_bool_primitives(self): + self.assertTrue(c._to_primitive_inst(True, "bool", "bool", [])) + self.assertTrue(c._to_inst(True, "bool", "bool")) + self.assertFalse(c._to_primitive_inst(False, "bool", "bool", [])) + self.assertFalse(c._to_inst(False, "bool", "bool")) + + def test_float_primitives(self): + for msg in [0.12341234 + i for i in range(-100, 100)]: + for rostype in ["float32", "float64"]: + self.assertEqual(c._to_primitive_inst(msg, rostype, rostype, []), msg) + self.assertEqual(c._to_inst(msg, rostype, rostype), msg) + c._to_inst(msg, rostype, rostype) + + def test_float_special_cases(self): + for msg in [1e9999999, -1e9999999, float("nan")]: + for rostype in ["float32", "float64"]: + self.assertEqual(c._from_inst(msg, rostype), None) + self.assertEqual(dumps({"data": c._from_inst(msg, rostype)}), '{"data": null}') + + def test_signed_int_base_msgs(self): + int8s = range(-127, 128) + for int8 in int8s: + self.do_primitive_test(int8, "std_msgs/Int8") + self.do_primitive_test(int8, "std_msgs/Int16") + self.do_primitive_test(int8, "std_msgs/Int32") + self.do_primitive_test(int8, "std_msgs/Int64") + + int16s = [-32767, 32767] + for int16 in int16s: + self.do_primitive_test(int16, "std_msgs/Int16") + self.do_primitive_test(int16, "std_msgs/Int32") + self.do_primitive_test(int16, "std_msgs/Int64") + self.assertRaises(Exception, self.do_primitive_test, int16, "std_msgs/Int8") + + int32s = [-2147483647, 2147483647] + for int32 in int32s: + self.do_primitive_test(int32, "std_msgs/Int32") + self.do_primitive_test(int32, "std_msgs/Int64") + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Int8") + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Int16") + + int64s = [-9223372036854775807, 9223372036854775807] + for int64 in int64s: + self.do_primitive_test(int64, "std_msgs/Int64") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int8") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int16") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Int32") + + def test_unsigned_int_base_msgs(self): + int8s = range(0, 256) + for int8 in int8s: + self.do_primitive_test(int8, "std_msgs/Char") + self.do_primitive_test(int8, "std_msgs/UInt8") + self.do_primitive_test(int8, "std_msgs/UInt16") + self.do_primitive_test(int8, "std_msgs/UInt32") + self.do_primitive_test(int8, "std_msgs/UInt64") + + int16s = [32767, 32768, 65535] + for int16 in int16s: + self.do_primitive_test(int16, "std_msgs/UInt16") + self.do_primitive_test(int16, "std_msgs/UInt32") + self.do_primitive_test(int16, "std_msgs/UInt64") + self.assertRaises(Exception, self.do_primitive_test, int16, "std_msgs/Char") + self.assertRaises(Exception, self.do_primitive_test, int16, "std_msgs/UInt8") + + int32s = [2147483647, 2147483648, 4294967295] + for int32 in int32s: + self.do_primitive_test(int32, "std_msgs/UInt32") + self.do_primitive_test(int32, "std_msgs/UInt64") + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/Char") + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/UInt8") + self.assertRaises(Exception, self.do_primitive_test, int32, "std_msgs/UInt16") + + int64s = [ + 4294967296, + 9223372036854775807, + 9223372036854775808, + 18446744073709551615, + ] + for int64 in int64s: + self.do_primitive_test(int64, "std_msgs/UInt64") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/Char") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt8") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt16") + self.assertRaises(Exception, self.do_primitive_test, int64, "std_msgs/UInt32") + + def test_byte_base_msg(self): + int8s = range(0, 256) + for int8 in int8s: + self.do_byte_test(int8, "std_msgs/Byte") + + def test_bool_base_msg(self): + self.do_primitive_test(True, "std_msgs/Bool") + self.do_primitive_test(False, "std_msgs/Bool") + + def test_string_base_msg(self): + for x in c.ros_primitive_types: + self.do_primitive_test(x, "std_msgs/String") + + def test_time_msg(self): + now_inst = c._to_inst("now", "builtin_interfaces/Time", "builtin_interfaces/Time") + self.assertTrue("sec" in now_inst.get_fields_and_field_types()) + self.assertTrue("nanosec" in now_inst.get_fields_and_field_types()) + + msg = {"sec": 3, "nanosec": 5} + self.do_test(msg, "builtin_interfaces/Time") + + msg = {"times": [{"sec": 3, "nanosec": 5}, {"sec": 2, "nanosec": 7}]} + self.do_test(msg, "rosbridge_test_msgs/TestTimeArray") + + # For ROS1 compatibility + inst1 = c._to_inst( + {"sec": 3, "nanosec": 5}, "builtin_interfaces/Time", "builtin_interfaces/Time" + ) + inst2 = c._to_inst( + {"secs": 3, "nsecs": 5}, "builtin_interfaces/Time", "builtin_interfaces/Time" + ) + self.assertEqual(inst1, inst2) + + def test_duration_msg(self): + msg = {"sec": 3, "nanosec": 5} + self.do_test(msg, "builtin_interfaces/Duration") + + msg = {"durations": [{"sec": 3, "nanosec": 5}, {"sec": 2, "nanosec": 7}]} + self.do_test(msg, "rosbridge_test_msgs/TestDurationArray") + + def test_header_msg(self): + msg = { + "stamp": {"sec": 12347, "nanosec": 322304}, + "frame_id": "2394dnfnlcx;v[p234j]", + } + self.do_test(msg, "std_msgs/Header") + + msg = {"header": msg} + self.do_test(msg, "rosbridge_test_msgs/TestHeader") + self.do_test(msg, "rosbridge_test_msgs/TestHeaderTwo") + + msg = {"header": [msg["header"], msg["header"], msg["header"]]} + self.do_test(msg, "rosbridge_test_msgs/TestHeaderArray") + + def test_assorted_msgs(self): + assortedmsgs = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "std_msgs/String", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] + for rostype in assortedmsgs: + inst = ros_loader.get_message_instance(rostype) + msg = c.extract_values(inst) + self.do_test(msg, rostype) + _ = loads(dumps(msg)) + inst2 = ros_loader.get_message_instance(rostype) + c.populate_instance(msg, inst2) + self.assertEqual(inst, inst2) + + def test_int8array(self): + def test_int8_msg(rostype, data): + msg = {"data": data} + inst = ros_loader.get_message_instance(rostype) + c.populate_instance(msg, inst) + self.validate_instance(inst) + return inst.data + + for msgtype in ["TestChar", "TestUInt8"]: + rostype = "rosbridge_test_msgs/" + msgtype + + # From List[int] + int8s = list(range(0, 256)) + ret = test_int8_msg(rostype, int8s) + np.testing.assert_array_equal(ret, np.array(int8s)) + + # From base64 string + b64str_int8s = standard_b64encode(bytes(int8s)).decode("ascii") + ret = test_int8_msg(rostype, b64str_int8s) + np.testing.assert_array_equal(ret, np.array(int8s)) + + for msgtype in ["TestUInt8FixedSizeArray16"]: + rostype = "rosbridge_test_msgs/" + msgtype + + # From List[int] + int8s = list(range(0, 16)) + ret = test_int8_msg(rostype, int8s) + np.testing.assert_array_equal(ret, np.array(int8s)) + + # From base64 string + b64str_int8s = standard_b64encode(bytes(int8s)).decode("ascii") + ret = test_int8_msg(rostype, b64str_int8s) + np.testing.assert_array_equal(ret, np.array(int8s)) + + def test_float32array(self): + def test_float32_msg(rostype, data): + msg = {"data": data} + inst = ros_loader.get_message_instance(rostype) + c.populate_instance(msg, inst) + self.validate_instance(inst) + return inst.data + + for msgtype in ["TestFloat32Array"]: + rostype = "rosbridge_test_msgs/" + msgtype + + # From List[float] + floats = list(map(float, range(0, 256))) + ret = test_float32_msg(rostype, floats) + np.testing.assert_array_equal(ret, np.array(floats)) + + # From List[int] + ints = list(map(int, range(0, 256))) + ret = test_float32_msg(rostype, ints) + np.testing.assert_array_equal(ret, np.array(ints)) + + for msgtype in ["TestFloat32BoundedArray"]: + rostype = "rosbridge_test_msgs/" + msgtype + + # From List[float] + floats = list(map(float, range(0, 16))) + ret = test_float32_msg(rostype, floats) + np.testing.assert_array_equal(ret, np.array(floats)) + + # From List[int] + ints = list(map(int, range(0, 16))) + ret = test_float32_msg(rostype, ints) + np.testing.assert_array_equal(ret, np.array(ints)) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_outgoing_message.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_outgoing_message.py new file mode 100755 index 000000000..08d6cf601 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_outgoing_message.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +import unittest + +import rostest +from rosbridge_library.internal.outgoing_message import OutgoingMessage +from std_msgs.msg import String + + +class TestOutgoingMessage(unittest.TestCase): + def test_json_values(self): + msg = String(data="foo") + outgoing = OutgoingMessage(msg) + + result = outgoing.get_json_values() + self.assertEqual(result["data"], msg.data) + + again = outgoing.get_json_values() + self.assertTrue(result is again) + + def test_cbor_values(self): + msg = String(data="foo") + outgoing = OutgoingMessage(msg) + + result = outgoing.get_cbor_values() + self.assertEqual(result["data"], msg.data) + + again = outgoing.get_cbor_values() + self.assertTrue(result is again) + + +PKG = "rosbridge_library" +NAME = "test_outgoing_message" +if __name__ == "__main__": + rostest.unitrun(PKG, NAME, TestOutgoingMessage) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_ros_loader.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_ros_loader.py new file mode 100755 index 000000000..d808efc66 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_ros_loader.py @@ -0,0 +1,334 @@ +#!/usr/bin/env python +import unittest + +from rosbridge_library.internal import ros_loader +from rosidl_runtime_py.utilities import get_message + + +class TestROSLoader(unittest.TestCase): + def test_bad_msgnames(self): + bad = [ + "", + "/", + "//", + "///", + "////", + "/////", + "bad", + "stillbad", + "better/", + "better//", + "better///", + "/better", + "//better", + "///better", + r"this\isbad", + "\\", + ] + for x in bad: + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_message_class, x + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_message_instance, x + ) + + def test_irregular_msgnames(self): + irregular = [ + "std_msgs//String", + "//std_msgs/String", + "/std_msgs//String", + "/std_msgs/String", + "//std_msgs//String", + "/std_msgs/String/", + "//std_msgs//String//", + "std_msgs/String/", + "std_msgs//String//", + ] + for x in irregular: + self.assertNotEqual(ros_loader.get_message_class(x), None) + self.assertNotEqual(ros_loader.get_message_instance(x), None) + + def test_std_msgnames(self): + stdmsgs = [ + "std_msgs/Bool", + "std_msgs/Byte", + "std_msgs/ByteMultiArray", + "std_msgs/ColorRGBA", + "std_msgs/Empty", + "std_msgs/Float32", + "std_msgs/Float32MultiArray", + "std_msgs/Float64", + "std_msgs/Header", + "std_msgs/Int16", + "std_msgs/Int16MultiArray", + "std_msgs/Int32", + "std_msgs/Int32MultiArray", + "std_msgs/Int64", + "std_msgs/Int64MultiArray", + "std_msgs/Int8", + "std_msgs/Int8MultiArray", + "std_msgs/MultiArrayDimension", + "std_msgs/MultiArrayLayout", + "std_msgs/String", + "std_msgs/UInt16", + "std_msgs/UInt16MultiArray", + "std_msgs/UInt32MultiArray", + "std_msgs/UInt64MultiArray", + "std_msgs/UInt32", + "std_msgs/UInt64", + "std_msgs/UInt8", + "std_msgs/UInt8MultiArray", + ] + for x in stdmsgs: + self.assertNotEqual(ros_loader.get_message_class(x), None) + inst = ros_loader.get_message_instance(x) + self.assertNotEqual(inst, None) + self.assertEqual(get_message(x), type(inst)) + + def test_msg_cache(self): + stdmsgs = [ + "std_msgs/Bool", + "std_msgs/Byte", + "std_msgs/ByteMultiArray", + "std_msgs/ColorRGBA", + "std_msgs/Empty", + "std_msgs/Float32", + "std_msgs/Float32MultiArray", + "std_msgs/Float64", + "std_msgs/Header", + "std_msgs/Int16", + "std_msgs/Int16MultiArray", + "std_msgs/Int32", + "std_msgs/Int32MultiArray", + "std_msgs/Int64", + "std_msgs/Int64MultiArray", + "std_msgs/Int8", + "std_msgs/Int8MultiArray", + "std_msgs/MultiArrayDimension", + "std_msgs/MultiArrayLayout", + "std_msgs/String", + "std_msgs/UInt16", + "std_msgs/UInt16MultiArray", + "std_msgs/UInt32MultiArray", + "std_msgs/UInt64MultiArray", + "std_msgs/UInt32", + "std_msgs/UInt64", + "std_msgs/UInt8", + "std_msgs/UInt8MultiArray", + ] + for x in stdmsgs: + self.assertNotEqual(ros_loader.get_message_class(x), None) + inst = ros_loader.get_message_instance(x) + self.assertNotEqual(inst, None) + self.assertEqual(get_message(x), type(inst)) + self.assertTrue(x in ros_loader._loaded_msgs) + + def test_assorted_msgnames(self): + assortedmsgs = [ + "geometry_msgs/Pose", + "actionlib_msgs/GoalStatus", + "geometry_msgs/WrenchStamped", + "stereo_msgs/DisparityImage", + "nav_msgs/OccupancyGrid", + "geometry_msgs/Point32", + "std_msgs/String", + "trajectory_msgs/JointTrajectoryPoint", + "diagnostic_msgs/KeyValue", + "visualization_msgs/InteractiveMarkerUpdate", + "nav_msgs/GridCells", + "sensor_msgs/PointCloud2", + ] + for x in assortedmsgs: + self.assertNotEqual(ros_loader.get_message_class(x), None) + inst = ros_loader.get_message_instance(x) + self.assertNotEqual(inst, None) + self.assertEqual(get_message(x), type(inst)) + + def test_invalid_msgnames_primitives(self): + invalid = [ + "bool", + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + "string", + "time", + "duration", + ] + for x in invalid: + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_message_class, x + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, + ros_loader.get_message_instance, + x, + ) + + def test_nonexistent_packagenames(self): + nonexistent = [ + "wangle_msgs/Jam", + "whistleblower_msgs/Document", + "coercion_msgs/Bribe", + "airconditioning_msgs/Cold", + "pr2thoughts_msgs/Escape", + ] + for x in nonexistent: + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_message_class, x) + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_message_instance, x) + + def test_packages_without_msgs(self): + no_msgs = [ + "roslib/Time", + "roslib/Duration", + "roslib/Header", + "std_srvs/ConflictedMsg", + ] + for x in no_msgs: + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_message_class, x) + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_message_instance, x) + + def test_nonexistent_msg_classnames(self): + nonexistent = [ + "rcl_interfaces/Time", + "rcl_interfaces/Duration", + "rcl_interfaces/Header", + "std_msgs/Spool", + "geometry_msgs/Tetrahedron", + "sensor_msgs/TelepathyUnit", + ] + for x in nonexistent: + self.assertRaises(ros_loader.InvalidClassException, ros_loader.get_message_class, x) + self.assertRaises(ros_loader.InvalidClassException, ros_loader.get_message_instance, x) + + def test_bad_servicenames(self): + bad = [ + "", + "/", + "//", + "///", + "////", + "/////", + "bad", + "stillbad", + "not/better/even/still", + "not//better//even//still", + "not///better///even///still", + "better/", + "better//", + "better///", + "/better", + "//better", + "///better", + r"this\isbad", + "\\", + ] + for x in bad: + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_service_class, x + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_service_request_instance, x + ) + self.assertRaises( + ros_loader.InvalidTypeStringException, ros_loader.get_service_response_instance, x + ) + + def test_irregular_servicenames(self): + irregular = [ + "rcl_interfaces//GetParameters", + "/rcl_interfaces/GetParameters/", + "/rcl_interfaces/GetParameters", + "//rcl_interfaces/GetParameters", + "/rcl_interfaces//GetParameters", + "rcl_interfaces/GetParameters//", + "/rcl_interfaces/GetParameters//", + "rcl_interfaces/GetParameters/", + "rcl_interfaces//GetParameters//", + ] + for x in irregular: + self.assertNotEqual(ros_loader.get_service_class(x), None) + self.assertNotEqual(ros_loader.get_service_request_instance(x), None) + self.assertNotEqual(ros_loader.get_service_response_instance(x), None) + + def test_common_servicenames(self): + common = [ + "rcl_interfaces/GetParameters", + "rcl_interfaces/SetParameters", + "std_srvs/Empty", + "nav_msgs/GetMap", + "nav_msgs/GetPlan", + "sensor_msgs/SetCameraInfo", + "tf2_msgs/FrameGraph", + "example_interfaces/AddTwoInts", + ] + for x in common: + self.assertNotEqual(ros_loader.get_service_class(x), None) + self.assertNotEqual(ros_loader.get_service_request_instance(x), None) + self.assertNotEqual(ros_loader.get_service_response_instance(x), None) + + def test_srv_cache(self): + common = [ + "rcl_interfaces/GetParameters", + "rcl_interfaces/SetParameters", + "std_srvs/Empty", + "nav_msgs/GetMap", + "nav_msgs/GetPlan", + "sensor_msgs/SetCameraInfo", + "tf2_msgs/FrameGraph", + "example_interfaces/AddTwoInts", + ] + for x in common: + self.assertNotEqual(ros_loader.get_service_class(x), None) + self.assertNotEqual(ros_loader.get_service_request_instance(x), None) + self.assertNotEqual(ros_loader.get_service_response_instance(x), None) + self.assertTrue(x in ros_loader._loaded_srvs) + + def test_packages_without_srvs(self): + no_msgs = ["roslib/A", "roslib/B", "roslib/C", "std_msgs/CuriousSrv"] + for x in no_msgs: + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_service_class, x) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_service_request_instance, x + ) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_service_response_instance, x + ) + + def test_nonexistent_service_packagenames(self): + nonexistent = [ + "butler_srvs/FetchDrink", + "money_srvs/MoreMoney", + "snoopdogg_srvs/SipOnGinAndJuice", + "revenge_srvs/BackStab", + ] + for x in nonexistent: + self.assertRaises(ros_loader.InvalidModuleException, ros_loader.get_service_class, x) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_service_request_instance, x + ) + self.assertRaises( + ros_loader.InvalidModuleException, ros_loader.get_service_response_instance, x + ) + + def test_nonexistent_service_classnames(self): + nonexistent = [ + "std_srvs/Reboot", + "std_srvs/Full", + "nav_msgs/LoseMap", + ] + for x in nonexistent: + self.assertRaises(ros_loader.InvalidClassException, ros_loader.get_service_class, x) + self.assertRaises( + ros_loader.InvalidClassException, ros_loader.get_service_request_instance, x + ) + self.assertRaises( + ros_loader.InvalidClassException, ros_loader.get_service_response_instance, x + ) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_services.py b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_services.py new file mode 100755 index 000000000..d96638bf3 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/internal/test_services.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +import random +import time +import unittest + +import numpy as np +import rclpy +from rcl_interfaces.srv import ListParameters +from rclpy.node import Node +from rosbridge_library.internal import message_conversion as c +from rosbridge_library.internal import ros_loader, services +from rosbridge_library.internal.message_conversion import FieldTypeMismatchException + + +def populate_random_args(d): + # Given a dictionary d, replaces primitives with random values + if isinstance(d, dict): + for x in d: + d[x] = populate_random_args(d[x]) + return d + elif isinstance(d, str): + return str(random.random()) + elif isinstance(d, bool): + return True + elif isinstance(d, int): + return random.randint(100, 200) + elif isinstance(d, float): + return 3.5 + else: + return d + + +class ServiceTester: + def __init__(self, name, srv_type): + self.name = name + self.node = Node("service_tester_" + srv_type.replace("/", "_")) + self.srvClass = ros_loader.get_service_class(srv_type) + self.service = self.node.create_service(self.srvClass, name, self.callback) + + def start(self): + req = self.srvClass.Request() + gen = c.extract_values(req) + gen = populate_random_args(gen) + self.input = gen + thread = services.ServiceCaller(self.name, gen, self.success, self.error, self.node) + thread.start() + thread.join() + + def callback(self, req, res): + self.req = req + time.sleep(0.5) + gen = c.extract_values(res) + gen = populate_random_args(gen) + try: + res = c.populate_instance(gen, res) + except: # noqa: E722 # Will print() and raise + print("populating instance") + print(res) + print("populating with") + print(gen) + raise + self.output = gen + return res + + def success(self, rsp): + self.rsp = rsp + + def error(self, exc): + self.exc = exc + + def validate(self, equality_function): + if hasattr(self, "exc"): + print(self.exc) + raise self.exc + equality_function(self.input, c.extract_values(self.req)) + equality_function(self.output, self.rsp) + + +class TestServices(unittest.TestCase): + def setUp(self): + rclpy.init() + self.node = Node("test_node") + + def tearDown(self): + rclpy.shutdown() + + def msgs_equal(self, msg1, msg2): + if isinstance(msg1, str) and isinstance(msg2, str): + pass + else: + self.assertEqual(type(msg1), type(msg2)) + if type(msg1) in c.list_types: + for x, y in zip(msg1, msg2): + self.msgs_equal(x, y) + elif type(msg1) in c.primitive_types or type(msg1) is str: + self.assertEqual(msg1, msg2) + elif np.issubdtype(type(msg1), np.number): + self.assertEqual(msg1, msg2) + else: + for x in msg1: + self.assertTrue(x in msg2) + for x in msg2: + self.assertTrue(x in msg1) + for x in msg1: + self.msgs_equal(msg1[x], msg2[x]) + + def test_populate_request_args(self): + # Test empty messages + for srv_type in ["TestEmpty", "TestResponseOnly"]: + cls = ros_loader.get_service_class("rosbridge_test_msgs/" + srv_type) + for args in [[], {}, None]: + # Should throw no exceptions + services.args_to_service_request_instance("", cls.Request(), args) + + # Test msgs with data message + for srv_type in ["TestRequestOnly", "TestRequestAndResponse"]: + cls = ros_loader.get_service_class("rosbridge_test_msgs/" + srv_type) + for args in [[3], {"data": 3}]: + # Should throw no exceptions + services.args_to_service_request_instance("", cls.Request(), args) + self.assertRaises( + FieldTypeMismatchException, + services.args_to_service_request_instance, + "", + cls.Request(), + ["hello"], + ) + + # Test message with multiple fields + cls = ros_loader.get_service_class("rosbridge_test_msgs/TestMultipleRequestFields") + for args in [ + [3, 3.5, "hello", False], + {"int_value": 3, "float_value": 3.5, "string": "hello", "bool_value": False}, + ]: + # Should throw no exceptions + services.args_to_service_request_instance("", cls.Request(), args) + + def test_service_call(self): + """Test a simple list_parameters service call""" + # Prepare parameter + self.node.declare_parameter("test_parameter", 1.0) + + # First, call the service the 'proper' way + p = self.node.create_client(ListParameters, self.node.get_name() + "/list_parameters") + p.wait_for_service(0.5) + ret = p.call_async(ListParameters.Request()) + rclpy.spin_until_future_complete(self.node, ret) + + # Now, call using the services + json_ret = services.call_service(self.node, self.node.get_name() + "/list_parameters") + for x, y in zip(ret.result().result.names, json_ret["result"]["names"]): + self.assertEqual(x, y) + + def test_service_caller(self): + """Same as test_service_call but via the thread caller""" + # Prepare parameter + self.node.declare_parameter("test_parameter", 1.0) + + # First, call the service the 'proper' way + p = self.node.create_client(ListParameters, self.node.get_name() + "/list_parameters") + p.wait_for_service(0.5) + ret = p.call_async(ListParameters.Request()) + rclpy.spin_until_future_complete(self.node, ret) + + rcvd = {"json": None} + + def success(json): + rcvd["json"] = json + + def error(): + raise Exception() + + # Now, call using the services + services.ServiceCaller( + self.node.get_name() + "/list_parameters", None, success, error, self.node + ).start() + + time.sleep(0.5) + + for x, y in zip(ret.result().result.names, rcvd["json"]["result"]["names"]): + self.assertEqual(x, y) + + def test_service_tester(self): + t = ServiceTester("/test_service_tester", "rosbridge_test_msgs/TestRequestAndResponse") + t.start() + time.sleep(1.0) + t.validate(self.msgs_equal) + + def test_service_tester_alltypes(self): + ts = [] + for srv in [ + "TestResponseOnly", + "TestEmpty", + "TestRequestAndResponse", + "TestRequestOnly", + "TestMultipleResponseFields", + "TestMultipleRequestFields", + "TestArrayRequest", + ]: + t = ServiceTester("/test_service_tester_alltypes_" + srv, "rosbridge_test_msgs/" + srv) + t.start() + ts.append(t) + + time.sleep(1.0) + + for t in ts: + t.validate(self.msgs_equal) + + def test_random_service_types(self): + common = [ + "rcl_interfaces/ListParameters", + "rcl_interfaces/SetParameters", + "std_srvs/Empty", + "nav_msgs/GetMap", + "nav_msgs/GetPlan", + "sensor_msgs/SetCameraInfo", + "tf2_msgs/FrameGraph", + "example_interfaces/AddTwoInts", + ] + ts = [] + for srv in common: + t = ServiceTester("/test_random_service_types/" + srv, srv) + t.start() + ts.append(t) + + time.sleep(1.0) + + for t in ts: + t.validate(self.msgs_equal) diff --git a/src/interface/rosbridge_suite/rosbridge_library/test/test_all.test b/src/interface/rosbridge_suite/rosbridge_library/test/test_all.test new file mode 100644 index 000000000..270e16875 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_library/test/test_all.test @@ -0,0 +1,4 @@ + + + + diff --git a/src/interface/rosbridge_suite/rosbridge_msgs/CHANGELOG.rst b/src/interface/rosbridge_suite/rosbridge_msgs/CHANGELOG.rst new file mode 100644 index 000000000..460879f19 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_msgs/CHANGELOG.rst @@ -0,0 +1,68 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosbridge_msgs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.3.1 (2022-10-21) +------------------ + +1.3.0 (2022-08-16) +------------------ + +1.2.0 (2022-05-20) +------------------ + +1.1.2 (2022-01-03) +------------------ + +1.1.1 (2021-12-09) +------------------ + +1.1.0 (2021-10-22) +------------------ + +1.0.8 (2021-08-26) +------------------ + +1.0.7 (2021-08-18) +------------------ + +1.0.6 (2021-08-17) +------------------ + +1.0.5 (2021-08-12) +------------------ + +1.0.4 (2021-08-11) +------------------ + +1.0.3 (2021-08-03) +------------------ + +1.0.2 (2019-09-24) +------------------ + +1.0.1 (2019-09-20) +------------------ + +1.0.0 (2019-09-19) +------------------ +* Port to ROS 2 + +0.11.3 (2019-08-07) +------------------- + +0.11.2 (2019-07-08) +------------------- + +0.11.1 (2019-05-08) +------------------- + +0.11.0 (2019-03-29) +------------------- +* Additional client information websocket (`#393 `_) + * Add package rosbridge_msgs. + * rosbridge_server: Publish additional information about connected clients. + * rosbridge_server: Make ClientManager's add_client/remove_client methods thread safe. + * rosbridge_server: Rm unnecessary publishing. + * rosbridge_msgs: Cleanup/fix dependencies. +* Contributors: Hans-Joachim Krauch diff --git a/src/interface/rosbridge_suite/rosbridge_msgs/CMakeLists.txt b/src/interface/rosbridge_suite/rosbridge_msgs/CMakeLists.txt new file mode 100644 index 000000000..9403901a8 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_msgs/CMakeLists.txt @@ -0,0 +1,20 @@ +cmake_minimum_required(VERSION 3.5) +project(rosbridge_msgs) + +find_package(ament_cmake_ros REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +rosidl_generate_interfaces(${PROJECT_NAME} + msg/ConnectedClient.msg + msg/ConnectedClients.msg + DEPENDENCIES builtin_interfaces +) + +ament_export_dependencies(rosidl_default_runtime) + +ament_package() diff --git a/src/interface/rosbridge_suite/rosbridge_msgs/msg/ConnectedClient.msg b/src/interface/rosbridge_suite/rosbridge_msgs/msg/ConnectedClient.msg new file mode 100644 index 000000000..8eedbf287 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_msgs/msg/ConnectedClient.msg @@ -0,0 +1,2 @@ +string ip_address +builtin_interfaces/Time connection_time diff --git a/src/interface/rosbridge_suite/rosbridge_msgs/msg/ConnectedClients.msg b/src/interface/rosbridge_suite/rosbridge_msgs/msg/ConnectedClients.msg new file mode 100644 index 000000000..bbabfcf47 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_msgs/msg/ConnectedClients.msg @@ -0,0 +1 @@ +ConnectedClient[] clients diff --git a/src/interface/rosbridge_suite/rosbridge_msgs/package.xml b/src/interface/rosbridge_suite/rosbridge_msgs/package.xml new file mode 100644 index 000000000..8c22bba01 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_msgs/package.xml @@ -0,0 +1,24 @@ + + + rosbridge_msgs + 1.3.1 + Package containing message files + + Hans-Joachim Krauch + Hans-Joachim Krauch + Foxglove + + BSD + + ament_cmake_ros + rosidl_default_generators + + builtin_interfaces + rosidl_default_runtime + + rosidl_interface_packages + + + ament_cmake + + diff --git a/src/interface/rosbridge_suite/rosbridge_server/CHANGELOG.rst b/src/interface/rosbridge_suite/rosbridge_server/CHANGELOG.rst new file mode 100644 index 000000000..b9332eb3d --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/CHANGELOG.rst @@ -0,0 +1,569 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosbridge_server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.3.1 (2022-10-21) +------------------ +* Fix exceptions not being handled correctly. (`#817 `_) +* Skip unnecessary conversion for cbor/cbor-raw compression (`#792 `_) (`#800 `_) +* Improve robustness for multiple client connections (`#803 `_) +* Minor performance improvements (`#809 `_) +* Fix hostname parameter is no longer converted as an int value (`#780 `_) +* Fix duplicate subscription created with wrong 'raw' attribute. (`#798 `_) +* Add graceful shutdown (`#794 `_) +* Contributors: Hans-Joachim Krauch, Hugo Perier, Steffen Nattke + +1.3.0 (2022-08-16) +------------------ +* Add url_path config option (`#709 `_) +* Contributors: Matthijs van der Burgh, Sirawat S + +1.2.0 (2022-05-20) +------------------ +* Fixed multiple subscriber on transient_local topic (`#723 `_) +* use uuid to ensure client id uniqueness (`#713 `_) +* Contributors: Jacob Bandes-Storch, Will, p0rys + +1.1.2 (2022-01-03) +------------------ +* [694] update DurabilityPolicy api that are being deprecated (`#695 `_) +* Contributors: Evan Flynn + +1.1.1 (2021-12-09) +------------------ +* Allow subscribing to any qos profile when creating a subscriber (`#690 `_) +* Fix and add test for multiple subscribers to same topic (`#687 `_) +* Delete unsupported TCP and UDP server implementations in ROS 2 branch (`#685 `_) +* Fix error when advertising duplicate service (`#683 `_) +* Fix incoming service calls (`#669 `_) +* Replace busy wait in AdvertiseService with async handler (`#666 `_) +* Refactor smoke test to make WebSocket test harness reusable (`#675 `_) +* Contributors: Domenic Rodriguez, Jacob Bandes-Storch, Roman Shtylman + +1.1.0 (2021-10-22) +------------------ +* Exit cleanly on SIGINT; remove sleep in test (`#667 `_) +* Fix unused variables: flake8 --select=F841 (`#623 `_) +* Fix undefined name in rosbridge_websocket (`#659 `_) +* Port `#464 `_, `#478 `_, `#496 `_, and `#502 `_ from ROS1 branch (`#663 `_) +* Add pre-commit, format with black and isort (`#648 `_) +* Contributors: Adrian Macneil, Christian Clauss, Domenic Rodriguez, Jacob Bandes-Storch, Kenji Miyake + +1.0.8 (2021-08-26) +------------------ +* Add missing test_depends and buildtool_depends +* Fix various Python code style and lint issues +* Contributors: Christian Clauss, Jacob Bandes-Storch + +1.0.7 (2021-08-18) +------------------ +* Fix typos discovered by codespell (`#600 `_) +* Contributors: Christian Clauss + +1.0.6 (2021-08-17) +------------------ +* Fix broken links in changelogs +* Contributors: Jacob Bandes-Storch + +1.0.5 (2021-08-12) +------------------ +* Fix globs in launch xml for ROS 2 pre-Galactic (`#589 `_) +* Remove authentication features and rosauth dependency (`#586 `_) + [rosauth](http://wiki.ros.org/rosauth) is not maintained for ROS 2, and has not been released for Galactic (https://github.com/GT-RAIL/rosauth/issues/35). Since the authentication feature is old and not commonly used, and since rosbridge_suite has not yet been released in Eloquent, Foxy, or Galactic, we decided to just remove the authentication features to unblock us from pushing releases. + To avoid breaking backwards compatibility, we will not publish the new version of rosbridge_suite for Dashing. +* The server now allows choosing `port:=0` to select an ephemeral port, and sets the port number in the `actual_port` ROS param. (`#585 `_) +* Contributors: Jacob Bandes-Storch + +1.0.4 (2021-08-11) +------------------ + +1.0.3 (2021-08-03) +------------------ +* Add cbor-raw compression support (`#574 `_, adapted from ROS 1 implementation `#452 `_) +* Adaptations to Eloquent [Again] (`#533 `_) + * increase spin period to 1000Hz to allow 1000 messages per second into the websocket + * allow interpreting int as float when needed + * better handling array.array and numpy arrays + * allow bytes and str websocket messages + * add boolean type + * handle type extraction of static array rostypes + * missing cls variable + Co-authored-by: Maximilian Matthe + Co-authored-by: CoRoLa generic + Co-authored-by: joshwapohlmann +* Contributors: Jacob Bandes-Storch, travipross + +1.0.2 (2019-09-24) +------------------ +* use Python 3 dependency keys (`#436 `_) + +1.0.1 (2019-09-20) +------------------ + +1.0.0 (2019-09-19) +------------------ +* Port to ROS 2 + +0.11.3 (2019-08-07) +------------------- +* Fixes `#418 `_: WebSocketClosedError Spam (`#423 `_) + * not raising WebSocketClosedError for old tornado versions +* Contributors: lennartdopatka + +0.11.2 (2019-07-08) +------------------- +* yield infinite lock (`#413 `_) +* Add settings for websocket timeout (`#410 `_) + * Add settings for websocket timeout + * Error handling of StreamClosedError +* Contributors: Aurélien Labate + +0.11.1 (2019-05-08) +------------------- + +0.11.0 (2019-03-29) +------------------- +* Additional client information websocket (`#393 `_) + * Add package rosbridge_msgs. + * rosbridge_server: Publish additional information about connected clients. + * rosbridge_server: Make ClientManager's add_client/remove_client methods thread safe. + * rosbridge_server: Rm unnecessary publishing. + * rosbridge_msgs: Cleanup/fix dependencies. +* Handle BadYieldError in Tornado <4.5.0 (`#395 `_) +* Contributors: Hans-Joachim Krauch, Matt Vollrath + +0.10.2 (2019-03-04) +------------------- +* Log Tornado handler exceptions (`#386 `_) + * Decorate most handlers which were previously failing silently. + * Use a try block in the @coroutine, it refused double decoration. + * Always raise after logging, so Tornado sees the Exception too. + * Only warn when racing to write to a closed WebSocket. +* Synchronous websocket write (`#385 `_) + Fixes `#212 `_ +* Contributors: Matt Vollrath + +0.10.1 (2018-12-16) +------------------- + +0.10.0 (2018-12-14) +------------------- +* CBOR encoding (`#364 `_) + * Add CBOR encoding + * Fix value extraction performance regression + Extract message values once per message. + * Fix typed array tags + Was using big-endian tags and encoding little-endian. + Always use little-endian for now since Intel is prevalent for desktop. + Add some comments to this effect. + * Update CBOR protocol documentation + More information about draft typed arrays and when to use CBOR. + * Fix 64-bit integer CBOR packing + Use an actual 64-bit format. +* Add param to enable ws per-message deflate (`#365 `_) + * Add param to enable ws per-message deflate + Tornado has its own per-message deflate compression option, which + compresses each WebSocket message. The compression level should be + roughly equivalent to PNG compression, depending on whether the message is + JSON or binary (CBOR). The encoding/decoding time will be much faster + than protocol PNG compression. + This param should be enabled when wire size is important, e.g. not + connecting to localhost. +* rosbridge_server: Publish number of connected clients on latched topic. (`#359 `_) +* Fix a few problems (`#350 `_) + * xrange is not available in Python3, range works for both Python versions + * the variable v is undefined in search_param, comparing the implementation with the sibling functions I expect name to be the intended variable + * The module udp_handler is using the Authentication service but wasn't importing the module +* use package format 2, remove unnecessary dependencies (`#348 `_) +* Adding bson support for websockets (`#327 `_) + * removed message that bson isn't supported. setting the bson only mode class attribute + * added auth package inspection for bson only mode +* Contributors: Dirk Thomas, Hans-Joachim Krauch, Matt Vollrath, Sanic + +0.9.0 (2018-04-09) +------------------ +* Make unregister_timeout configurable (`#322 `_) + Pull request `#247 `_ introduces a 10 second delay to mitigate issue `#138 `_. + This change makes this delay configurable by passing an argument either + on the command line or when including a launch file. + Usage example: + ```xml + + + + + + ``` + Closes `#320 `_ +* Remove tornado fork from source code and add python-tornado as run dependency (`#317 `_) + Release only for kinetic+ +* Fix bug that lost data while sending large packets (`#310 `_) + * fix bug that lost data while sending large packets +* Contributors: Jørgen Borgesen, MBlistein, WH-0501 + +0.8.6 (2017-12-08) +------------------ + +0.8.5 (2017-11-23) +------------------ +* Raise if inappropriate bson module is installed (Appease `#198 `_) (`#270 `_) + * Raise Exception if inappropriate bson module is installed (Related to `#198 `_) +* Add Python3 compatibility (`#300 `_) + * First pass at Python 3 compatibility + * message_conversion: Only call encode on a Python2 str or bytes type + * protocol.py: Changes for dict in Python3. Compatible with Python 2 too. + * More Python 3 fixes, all tests pass + * Move definition of string_types to rosbridge_library.util +* Contributors: Junya Hayashi, Kartik Mohta + +0.8.4 (2017-10-16) +------------------ + +0.8.3 (2017-09-11) +------------------ + +0.8.2 (2017-09-11) +------------------ + +0.8.1 (2017-08-30) +------------------ + +0.8.0 (2017-08-30) +------------------ +* Merge pull request `#281 `_ from RobotWebTools/expose_b64 + expose binary_encoder rosparam that was hidden in deep depth +* address review comment. more explicitly describe valid args +* correct the possible argument +* expose binary_encoder rosparam that was hidden in deep depth +* Merge pull request `#277 `_ from T045T/remove_nodelay_for_udp + don't try to set TCP nodelay option for UDP +* don't try to set TCP nodelay option for UDP +* Merge pull request `#273 `_ from Sanic/set_bson_only_flags + Set default for bson_only_mode in websocket handler and launch file. +* Set default for bson_only_mode in websocket handler and launch file. +* Merge pull request `#257 `_ from Sanic/bson-only-mode + Implemented a bson_only_mode flag for the TCP version of rosbridge +* Implemented a bson_only_mode flag for the TCP version of rosbridge; This allows you to switch to a full-duplex transmission of BSON messages and therefore eliminates the need for a base64 encoding of binary data; Use the new mode by starting:'roslaunch rosbridge_server rosbridge_tcp.launch bson_only_mode:=True' or passing '--bson_only_mode' to the rosbridge_tcp.py script +* Contributors: Adolfo Rodriguez Tsouroukdissian, Jihoon Lee, Nils Berg, Patrick Mania, pmania + +0.7.17 (2017-01-25) +------------------- +* Fixed the launch files for the tcp and udp service. Without these modifications, the rosapi node fails because some rosparams are not defined properly before. Now the launchfiles comply to the websocket version. +* Added default topics to all launch files, and fixed bug where it would crash if nothing was put into the lists as values +* Fix: Set default to publish all topics + Without better doc, one does not understand why no topics are published. I thought, something is broken. + With this defaults, everything is working out of the box. And for a more secure setup, one can change it. +* correct default values for security globs + also accept empty list as the default "do not check globs" value in addition to None. + Finally, append rosapi service glob after processing command line input so it's not overwritten +* add missing imports and correct default values for glob parameters +* Added services_glob to CallServices, added globs to rosbridge_tcp and rosbridge_udp, and other miscellaneous fixes. +* Two minor fixes. +* Added new parameters for topic and service security. + Added 3 new parameters to rosapi and rosbridge_server which filter the + topics, services, and parameters broadcast by the server to match an + array of glob strings. +* Contributors: Devon Ash, Eric, Nils Berg, Patrick Mania, plieningerweb + +0.7.16 (2016-08-15) +------------------- + +0.7.15 (2016-04-25) +------------------- +* Track Twisted run_depend + Fixes `#218 `_ +* Add rosbridge_udp cmake install rule `#225 `_ +* Stop UDP server on ROS shutdown +* changelog updated +* Track Twisted run_depend + Fixes `#218 `_ +* Contributors: Jihoon Lee, Matt Vollrath, Russell Toris + +0.7.14 (2016-02-11) +------------------- +* Abort websocket server listen() retry on shutdown + This allows the server to shut down via SIGINT or SIGTERM during its listen() retry loop. +* rospy.get_param instead of get_param +* actually use those parameters +* remove reference to retry_startup_delay from rosbridge_udp.launch +* clean up parameters and handling + * make parameters accessible via parameter server for all three versions + * remove old advertise_service parameters + * UDP and TCP can't do SSL + * TCP can't authenticate yet (because the RosbridgeTcpSocket class is instantiated for each request and hence does not hold state) + * UDP does not take a hostname or address, but rather an interface +* Allow TCP Server to reuse address after restart + After killing (Ctrl-C) a rosbridge_tcp server instance which has + connected clients, starting a new instance (on the same port) can + fail with the error: '[Errno 98] Address already in use'. Although the + node retries until the server starts, this can take up to a few minutes. + Instruct the ThreadingTCPServer to allow the reuse of the same address. +* Adding UDP +* Contributors: Matt Vollrath, Nils Berg, Victor Savu, XuHao, xuhao1 + +0.7.13 (2015-08-14) +------------------- +* Add bson encoding to the server side +* Add default strings for certfile and keyfile + This allows downstream packages with roslaunch_add_file_check tests to pass. +* Fix whitespace in RosbridgeTcpHandler +* Modularize RosbridgeTcpSocket +* Modularize RosbridgeWebSocket +* add shutdown handling to rosbridge_tcp and make rosbridge_websocket more robust +* Removed space from empty line. + Thanks @T045T +* Stop IOLoop on shutdown. +* Contributors: Benny, David Lu, Matt Vollrath, Nils Berg, Paul Bovbel + +0.7.12 (2015-04-07) +------------------- + +0.7.11 (2015-03-23) +------------------- +* rename rosapi script to rosapi_node to address `#170 `_ +* Enabled TCP nodelay in Websocket handler +* Contributors: Jihoon Lee, Sebastien Mamessier + +0.7.10 (2015-02-25) +------------------- + +0.7.9 (2015-02-24) +------------------ + +0.7.8 (2015-01-16) +------------------ +* Fix path to Tornado speedup extension source +* Build Tornado speedups + Fixes `#135 `_ +* Contributors: Matt Vollrath + +0.7.7 (2015-01-06) +------------------ +* remove rosbridge_tools from dependency `#163 `_ +* reverting back the changes +* Contributors: Jihoon Lee + +0.7.6 (2014-12-26) +------------------ +* 0.7.5 +* update changelog +* Function in robridge_tools for importing tornado +* Revert "reverts back to internal tornado until fix is ready" + This reverts commit 49eeb1d97da154213d3170c95169b5677b329d07. +* 0.7.4 +* changelog updated +* reverts back to internal tornado until fix is ready +* 0.7.3 +* changelog updated +* 0.7.2 +* changelog updated +* use alias to import rosbridge_tool tornado +* move modules under rosbridge_tools +* 0.7.1 +* update changelog +* Merge pull request #147 from RobotWebTools/migrate_third_parties + separate tornado and backports from rosbridge_server +* separate out third party library and ros related script +* remove setup.py +* add rosbridge_tools as rosbridge_server dependency +* remove python-imaging dependency. it is used in rosbridge_library +* 0.7.0 +* changelog updated +* Contributors: Jihoon Lee, Jon Binney, Russell Toris + +0.7.5 (2014-12-26) +------------------ +* Function in robridge_tools for importing tornado +* Revert "reverts back to internal tornado until fix is ready" + This reverts commit 49eeb1d97da154213d3170c95169b5677b329d07. +* Contributors: Jon Binney + +0.7.4 (2014-12-16) +------------------ +* reverts back to internal tornado until fix is ready +* Contributors: Russell Toris + +0.7.3 (2014-12-15) +------------------ + +0.7.2 (2014-12-15) +------------------ +* use alias to import rosbridge_tool tornado +* move modules under rosbridge_tools +* 0.7.1 +* update changelog +* Merge pull request #147 from RobotWebTools/migrate_third_parties + separate tornado and backports from rosbridge_server +* separate out third party library and ros related script +* remove setup.py +* add rosbridge_tools as rosbridge_server dependency +* remove python-imaging dependency. it is used in rosbridge_library +* Contributors: Jihoon Lee, Russell Toris + +0.7.1 (2014-12-09) +------------------ +* Merge pull request `#147 `_ from RobotWebTools/migrate_third_parties + separate tornado and backports from rosbridge_server +* separate out third party library and ros related script +* remove setup.py +* add rosbridge_tools as rosbridge_server dependency +* remove python-imaging dependency. it is used in rosbridge_library +* Contributors: Jihoon Lee, Russell Toris + +0.7.0 (2014-12-02) +------------------ + +0.6.8 (2014-11-05) +------------------ + +0.6.7 (2014-10-22) +------------------ +* updated package manifests +* Merge pull request #137 from RobotWebTools/revert + Revert "Install Tornado via rosdep" +* Revert "Install Tornado via rosdep" + This reverts commit 2d8a2fa5d23550427d6957acffc7dfa6f55e9c34. +* Contributors: Russell Toris + +0.6.6 (2014-10-21) +------------------ +* Install Tornado via rosdep + Use python-tornado-pip to make sure we get the speedups introduced in Tornado 3.2. +* Contributors: Matt Vollrath + +0.6.5 (2014-10-14) +------------------ +* 0.6.4 +* update changelog +* add backports to setup.py, so backports.ssl_match_hostname can be properly resolved +* 0.6.3 +* update change log +* Contributors: Jihoon Lee, Nils Berg + +0.6.4 (2014-10-08) +------------------ +* add backports to setup.py, so backports.ssl_match_hostname can be properly resolved +* Contributors: Nils Berg + +0.6.3 (2014-10-07) +------------------ + +0.6.2 (2014-10-06) +------------------ +* Merge pull request #125 from megawac/json + Remove unused imports; move json imports to utility +* override to enable support for allowing alternate origins + To accept all cross-origin traffic (which was the default prior to Tornado 4.0), simply override this method to always return true. +* import backports.ssl_match_hostname 3.4.0.2 +* upgrade tornado to 4.0.2 +* Remove unused json imports; move json imports to utility + Fixes #7 +* Contributors: Graeme Yeates, Ramon Wijnands, Russell Toris + +0.6.1 (2014-09-01) +------------------ + +0.6.0 (2014-05-23) +------------------ + +0.5.4 (2014-04-17) +------------------ + +0.5.3 (2014-03-28) +------------------ +* rosbridge_server: add install tag for python files, not just symlinks, to make them executable +* Contributors: ipa-mig + +0.5.2 (2014-03-14) +------------------ +* move global param into local param to address issue `#25 `_ +* moving global parameter into local parameter to address issue `#25 `_ +* merging changes of groovy-devel into hydro-devel +* Specific IP address binding using roslauch +* added parameter lookup to rosbridge_tcp.py, modules where those are used, and default parameters to launch file; internal default-values still get used when launch-file does not provide them; internal defaults can be changed within rosbridge_tcp.py +* increaing max_msg_length - still hardcoded +* preparing pull request for upstream.. +* cleanup: files, notes, some code +* cleanup tcp-server +* added message_field to allow client to control delay between messages from rosbridge +* tested rosbridge_websocket with new capabilities; websocket test scripts not working yet..; but new caps are working when using rosbridge_websocket and tcp2ws wrapper --> so only testscripts need to be fixed for websockets. +* feierabend.. morgen weiter mit server & client JSON-decoder, see notes +* only current changes; not yet done.. +* code cleanup, not yet finished..; rosbridge logging much cleaner now +* file extension for websocket server .py +* ... +* ... +* fixed test_server_defragment - recodegit status +* linuxonandroid +* added extension to server script; + symlink +* fixed some parts; ..still better do some redesign for queueing of messages.. +* forced tcp_send to use queue and use delay between sends +* blocking behavior for service requests to non-ros; test-scripts use get-ip4 helper function; ..needs a lot cleanup before next steps.. +* message_size debugging; TODO: sort list of received fragments! ; make sure receive_buffers are big enough for fragment_size + header.. +* some code cleanup +* some minor changes: comments, debug-output, .. +* first working classes: service_server +* added socket_timeout and exception-handling for clients that do not send any data at all but are listening only. +* Catkin fixes for rosbridge TCP. +* Catkinizes rosbridge_tcp. + Adds launch file too. +* Clean up of Rosbridge TCP. +* add rosbridge_server with tcp socket support +* adapt rosbridge_tcp to groovy-devel structure +* add rosbridge_server with tcp socket support +* Param bug fixed +* SSL options added +* Contributors: Brandon Alexander, Jihoon Lee, Russell Toris, Steffel Fenix, dave, fxm-db, ipa-fxm, root + +0.5.1 (2013-10-31) +------------------ + +0.5.0 (2013-07-17) +------------------ +* 0.5.0 preparation for hydro release +* Removes trailing commas. +* removing global bin installation in setup.py +* Contributors: Brandon Alexander, Jihoon Lee + +0.4.4 (2013-04-08) +------------------ + +0.4.3 (2013-04-03 08:24) +------------------------ + +0.4.2 (2013-04-03 08:12) +------------------------ +* launch file location fixed in install +* response from rosauth fixed +* authentication added +* launch file updated with args for port and SSL options +* SSL options added +* eclipse projects removed +* Contributors: Russell Toris + +0.4.1 (2013-03-07) +------------------ + +0.4.0 (2013-03-05) +------------------ +* Resolves submodule issues. +* Adds rosbridge_websocket launch file. +* Uses only 1 .gitignore to avoid confusion. +* Fixing rosapi's "Cannot include proxy..." errors. +* Renames server script to rosbridge_websocket. +* Adds BSD license header to code files. + See Issue `#13 `_. +* rosbridge_server requires rosapi. +* Moves rosbridge_server code to scripts. + Was getting an odd bug with tornado: + [ERROR] [WallTime: 1356115083.100585] Uncaught exception, closing connection. + [ERROR] [WallTime: 1356115083.100900] Exception in callback +* Removing ultrajson from rosbridge. + If JSON parsing becomes a performance bottle neck, we can re-add it. +* Refactors rosbridge_server. Adds scripts dir. +* Catkinizing rosbridge_library and server. +* Added command line --port argument. +* Collapse directory structure. +* Moved the packages inside a folder called rosbridge +* Initial commit of rosbridge_server +* Contributors: Austin Hendrix, Brandon Alexander, Jonathan Mace diff --git a/src/interface/rosbridge_suite/rosbridge_server/CMakeLists.txt b/src/interface/rosbridge_suite/rosbridge_server/CMakeLists.txt new file mode 100644 index 000000000..2e493ab53 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.5) +project(rosbridge_server) + +find_package(ament_cmake_ros REQUIRED) +find_package(ament_cmake_core REQUIRED) +find_package(ament_cmake_python REQUIRED) + +ament_python_install_package( + ${PROJECT_NAME} PACKAGE_DIR "src/${PROJECT_NAME}") + +ament_package() + +install(PROGRAMS + scripts/rosbridge_websocket.py + scripts/rosbridge_websocket + DESTINATION lib/${PROJECT_NAME} +) + +install(FILES + launch/rosbridge_websocket_launch.xml + DESTINATION share/${PROJECT_NAME}/launch +) + +if(BUILD_TESTING) + find_package(launch_testing_ament_cmake REQUIRED) + add_launch_test(test/websocket/advertise_service.test.py) + add_launch_test(test/websocket/call_service.test.py) + add_launch_test(test/websocket/smoke.test.py) + add_launch_test(test/websocket/transient_local_publisher.test.py) + add_launch_test(test/websocket/best_effort_publisher.test.py) + add_launch_test(test/websocket/multiple_subscribers_raw.test.py) +endif() diff --git a/src/interface/rosbridge_suite/rosbridge_server/launch/rosbridge_websocket_launch.xml b/src/interface/rosbridge_suite/rosbridge_server/launch/rosbridge_websocket_launch.xml new file mode 100644 index 000000000..30750e430 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/launch/rosbridge_websocket_launch.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/interface/rosbridge_suite/rosbridge_server/package.xml b/src/interface/rosbridge_suite/rosbridge_server/package.xml new file mode 100644 index 000000000..df92c66e1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/package.xml @@ -0,0 +1,38 @@ + + + rosbridge_server + 1.3.1 + A WebSocket interface to rosbridge. + + BSD + + http://ros.org/wiki/rosbridge_server + https://github.com/RobotWebTools/rosbridge_suite/issues + https://github.com/RobotWebTools/rosbridge_suite + + Jonathan Mace + Jihoon Lee + Foxglove + + ament_cmake + ament_cmake_ros + + python3-tornado + python3-twisted + rclpy + rosbridge_library + rosbridge_msgs + rosapi + + python3-autobahn + launch + launch_ros + launch_testing + launch_testing_ros + launch_testing_ament_cmake + std_srvs + + + ament_cmake + + diff --git a/src/interface/rosbridge_suite/rosbridge_server/scripts/rosbridge_websocket b/src/interface/rosbridge_suite/rosbridge_server/scripts/rosbridge_websocket new file mode 120000 index 000000000..647069442 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/scripts/rosbridge_websocket @@ -0,0 +1 @@ +rosbridge_websocket.py \ No newline at end of file diff --git a/src/interface/rosbridge_suite/rosbridge_server/scripts/rosbridge_websocket.py b/src/interface/rosbridge_suite/rosbridge_server/scripts/rosbridge_websocket.py new file mode 100755 index 000000000..ce4c9bd06 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/scripts/rosbridge_websocket.py @@ -0,0 +1,349 @@ +#!/usr/bin/env python3 +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + + +import sys +import time + +import rclpy +from rclpy.node import Node +from rclpy.qos import DurabilityPolicy, QoSProfile +from rosbridge_library.capabilities.advertise import Advertise +from rosbridge_library.capabilities.advertise_service import AdvertiseService +from rosbridge_library.capabilities.call_service import CallService +from rosbridge_library.capabilities.publish import Publish +from rosbridge_library.capabilities.subscribe import Subscribe +from rosbridge_library.capabilities.unadvertise_service import UnadvertiseService +from std_msgs.msg import Int32 +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop, PeriodicCallback +from tornado.netutil import bind_sockets +from tornado.web import Application + +from rosbridge_server import ClientManager, RosbridgeWebSocket + + +def start_hook(): + IOLoop.instance().start() + + +def shutdown_hook(): + IOLoop.instance().stop() + + +class RosbridgeWebsocketNode(Node): + def __init__(self): + super().__init__("rosbridge_websocket") + + RosbridgeWebSocket.node_handle = self + + ################################################## + # Parameter handling # + ################################################## + + self.protocol_parameter_handling() + + # get tornado application parameters + tornado_settings = {} + tornado_settings["websocket_ping_interval"] = float( + self.declare_parameter("websocket_ping_interval", 0).value + ) + tornado_settings["websocket_ping_timeout"] = float( + self.declare_parameter("websocket_ping_timeout", 30).value + ) + if "--websocket_ping_interval" in sys.argv: + idx = sys.argv.index("--websocket_ping_interval") + 1 + if idx < len(sys.argv): + tornado_settings["websocket_ping_interval"] = float(sys.argv[idx]) + else: + print("--websocket_ping_interval argument provided without a value.") + sys.exit(-1) + + if "--websocket_ping_timeout" in sys.argv: + idx = sys.argv.index("--websocket_ping_timeout") + 1 + if idx < len(sys.argv): + tornado_settings["websocket_ping_timeout"] = float(sys.argv[idx]) + else: + print("--websocket_ping_timeout argument provided without a value.") + sys.exit(-1) + + # Server and SSL options + # SSL options, cannot set default to None - rclpy throws warning + certfile = self.declare_parameter("certfile", "").value + keyfile = self.declare_parameter("keyfile", "").value + # if not set, set to None + if certfile == "": + certfile = None + if keyfile == "": + keyfile = None + + port = self.declare_parameter("port", 9090).value + if "--port" in sys.argv: + idx = sys.argv.index("--port") + 1 + if idx < len(sys.argv): + port = int(sys.argv[idx]) + else: + print("--port argument provided without a value.") + sys.exit(-1) + address = self.declare_parameter("address", "").value + if "--address" in sys.argv: + idx = sys.argv.index("--address") + 1 + if idx < len(sys.argv): + address = sys.argv[idx] + else: + print("--address argument provided without a value.") + sys.exit(-1) + + url_path = self.declare_parameter("url_path", "/").value + if "--url_path" in sys.argv: + idx = sys.argv.index("--url_path") + 1 + if idx < len(sys.argv): + url_path = str(sys.argv[idx]) + else: + print("--url_path argument provided without a value.") + sys.exit(-1) + + retry_startup_delay = self.declare_parameter("retry_startup_delay", 2.0).value # seconds. + if "--retry_startup_delay" in sys.argv: + idx = sys.argv.index("--retry_startup_delay") + 1 + if idx < len(sys.argv): + retry_startup_delay = int(sys.argv[idx]) + else: + print("--retry_startup_delay argument provided without a value.") + sys.exit(-1) + + ################################################## + # Done with parameter handling # + ################################################## + + handlers = [(r"/", RosbridgeWebSocket), (r"", RosbridgeWebSocket)] + if url_path != "/": + handlers = [(rf"{url_path}", RosbridgeWebSocket)] + + application = Application(handlers, **tornado_settings) + + connected = False + while not connected and self.context.ok(): + try: + ssl_options = None + if certfile is not None and keyfile is not None: + ssl_options = {"certfile": certfile, "keyfile": keyfile} + sockets = bind_sockets(port, address) + actual_port = sockets[0].getsockname()[1] + server = HTTPServer(application, ssl_options=ssl_options) + server.add_sockets(sockets) + self.declare_parameter("actual_port", actual_port) + self.get_logger().info(f"Rosbridge WebSocket server started on port {actual_port}") + connected = True + except OSError as e: + self.get_logger().warn( + "Unable to start server: {} " "Retrying in {}s.".format(e, retry_startup_delay) + ) + time.sleep(retry_startup_delay) + + def protocol_parameter_handling(self): + RosbridgeWebSocket.use_compression = self.declare_parameter("use_compression", False).value + + RosbridgeWebSocket.call_services_in_new_thread = self.declare_parameter( + "call_services_in_new_thread", False + ).value + + # get RosbridgeProtocol parameters + RosbridgeWebSocket.fragment_timeout = self.declare_parameter( + "fragment_timeout", RosbridgeWebSocket.fragment_timeout + ).value + + RosbridgeWebSocket.delay_between_messages = self.declare_parameter( + "delay_between_messages", RosbridgeWebSocket.delay_between_messages + ).value + + RosbridgeWebSocket.max_message_size = self.declare_parameter( + "max_message_size", RosbridgeWebSocket.max_message_size + ).value + + RosbridgeWebSocket.unregister_timeout = self.declare_parameter( + "unregister_timeout", RosbridgeWebSocket.unregister_timeout + ).value + + bson_only_mode = self.declare_parameter("bson_only_mode", False).value + + RosbridgeWebSocket.client_manager = ClientManager(self) + + # Publisher for number of connected clients + # QoS profile with transient local durability (latched topic in ROS 1). + client_count_qos_profile = QoSProfile( + depth=10, + durability=DurabilityPolicy.TRANSIENT_LOCAL, + ) + + RosbridgeWebSocket.client_count_pub = self.create_publisher( + Int32, "client_count", qos_profile=client_count_qos_profile + ) + RosbridgeWebSocket.client_count_pub.publish(Int32(data=0)) + + # Get the glob strings and parse them as arrays. + topics_glob = self.declare_parameter("topics_glob", "").value + + services_glob = self.declare_parameter("services_glob", "").value + + params_glob = self.declare_parameter("params_glob", "").value + + RosbridgeWebSocket.topics_glob = [ + element.strip().strip("'") + for element in topics_glob[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] + RosbridgeWebSocket.services_glob = [ + element.strip().strip("'") + for element in services_glob[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] + RosbridgeWebSocket.params_glob = [ + element.strip().strip("'") + for element in params_glob[1:-1].split(",") + if len(element.strip().strip("'")) > 0 + ] + + if "--fragment_timeout" in sys.argv: + idx = sys.argv.index("--fragment_timeout") + 1 + if idx < len(sys.argv): + RosbridgeWebSocket.fragment_timeout = int(sys.argv[idx]) + else: + print("--fragment_timeout argument provided without a value.") + sys.exit(-1) + + if "--delay_between_messages" in sys.argv: + idx = sys.argv.index("--delay_between_messages") + 1 + if idx < len(sys.argv): + RosbridgeWebSocket.delay_between_messages = float(sys.argv[idx]) + else: + print("--delay_between_messages argument provided without a value.") + sys.exit(-1) + + if "--max_message_size" in sys.argv: + idx = sys.argv.index("--max_message_size") + 1 + if idx < len(sys.argv): + value = sys.argv[idx] + RosbridgeWebSocket.max_message_size = int(value) + else: + print("--max_message_size argument provided without a value. (can be )") + sys.exit(-1) + + if "--unregister_timeout" in sys.argv: + idx = sys.argv.index("--unregister_timeout") + 1 + if idx < len(sys.argv): + RosbridgeWebSocket.unregister_timeout = float(sys.argv[idx]) + else: + print("--unregister_timeout argument provided without a value.") + sys.exit(-1) + + if "--topics_glob" in sys.argv: + idx = sys.argv.index("--topics_glob") + 1 + if idx < len(sys.argv): + value = sys.argv[idx] + if value == "None": + RosbridgeWebSocket.topics_glob = [] + else: + RosbridgeWebSocket.topics_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] + else: + print("--topics_glob argument provided without a value. (can be None or a list)") + sys.exit(-1) + + if "--services_glob" in sys.argv: + idx = sys.argv.index("--services_glob") + 1 + if idx < len(sys.argv): + value = sys.argv[idx] + if value == "None": + RosbridgeWebSocket.services_glob = [] + else: + RosbridgeWebSocket.services_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] + else: + print("--services_glob argument provided without a value. (can be None or a list)") + sys.exit(-1) + + if "--params_glob" in sys.argv: + idx = sys.argv.index("--params_glob") + 1 + if idx < len(sys.argv): + value = sys.argv[idx] + if value == "None": + RosbridgeWebSocket.params_glob = [] + else: + RosbridgeWebSocket.params_glob = [ + element.strip().strip("'") for element in value[1:-1].split(",") + ] + else: + print("--params_glob argument provided without a value. (can be None or a list)") + sys.exit(-1) + + if ("--bson_only_mode" in sys.argv) or bson_only_mode: + RosbridgeWebSocket.bson_only_mode = bson_only_mode + + # To be able to access the list of topics and services, you must be able to access the rosapi services. + if RosbridgeWebSocket.services_glob: + RosbridgeWebSocket.services_glob.append("/rosapi/*") + + Subscribe.topics_glob = RosbridgeWebSocket.topics_glob + Advertise.topics_glob = RosbridgeWebSocket.topics_glob + Publish.topics_glob = RosbridgeWebSocket.topics_glob + AdvertiseService.services_glob = RosbridgeWebSocket.services_glob + UnadvertiseService.services_glob = RosbridgeWebSocket.services_glob + CallService.services_glob = RosbridgeWebSocket.services_glob + + +def main(args=None): + if args is None: + args = sys.argv + + rclpy.init(args=args) + node = RosbridgeWebsocketNode() + + executor = rclpy.executors.SingleThreadedExecutor() + executor.add_node(node) + spin_callback = PeriodicCallback(lambda: executor.spin_once(timeout_sec=0.01), 1) + spin_callback.start() + try: + start_hook() + node.destroy_node() + rclpy.shutdown() + except KeyboardInterrupt: + print("Exiting due to SIGINT") + finally: + shutdown_hook() # shutdown hook to stop the server + + +if __name__ == "__main__": + main() diff --git a/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/__init__.py b/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/__init__.py new file mode 100644 index 000000000..fe3ed3131 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/__init__.py @@ -0,0 +1,2 @@ +from .client_mananger import ClientManager # noqa: F401 +from .websocket_handler import RosbridgeWebSocket # noqa: F401 diff --git a/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/client_mananger.py b/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/client_mananger.py new file mode 100644 index 000000000..651ed7082 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/client_mananger.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# Software License Agreement (BSD License) +# +# Copyright (c) 2018, Intermodalics +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Intermodalics nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +import threading + +from rclpy.clock import ROSClock +from rclpy.qos import DurabilityPolicy, QoSProfile +from std_msgs.msg import Int32 + +from rosbridge_msgs.msg import ConnectedClient, ConnectedClients + + +class ClientManager: + def __init__(self, node_handle): + qos = QoSProfile( + depth=1, + durability=DurabilityPolicy.TRANSIENT_LOCAL, + ) + + # Publisher for number of connected clients + self._client_count_pub = node_handle.create_publisher( + Int32, "client_count", qos_profile=qos + ) + # Publisher for connected clients + self._conn_clients_pub = node_handle.create_publisher( + ConnectedClients, "connected_clients", qos_profile=qos + ) + + self._lock = threading.Lock() + self._client_count = 0 + self._clients = {} + self.__publish() + + def __publish(self): + msg = ConnectedClients() + msg.clients = list(self._clients.values()) + self._conn_clients_pub.publish(msg) + self._client_count_pub.publish(Int32(data=len(msg.clients))) + + def add_client(self, client_id, ip_address): + with self._lock: + client = ConnectedClient() + client.ip_address = ip_address + client.connection_time = ROSClock().now().to_msg() + self._clients[client_id] = client + self.__publish() + + def remove_client(self, client_id, ip_address): + with self._lock: + self._clients.pop(client_id, None) + self.__publish() diff --git a/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/websocket_handler.py b/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/websocket_handler.py new file mode 100755 index 000000000..82db43257 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/src/rosbridge_server/websocket_handler.py @@ -0,0 +1,217 @@ +# Software License Agreement (BSD License) +# +# Copyright (c) 2012, Willow Garage, Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# * Neither the name of Willow Garage, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +import sys +import threading +import traceback +import uuid +from collections import deque +from functools import partial, wraps + +from rosbridge_library.rosbridge_protocol import RosbridgeProtocol +from rosbridge_library.util import bson +from tornado.ioloop import IOLoop +from tornado.iostream import StreamClosedError +from tornado.websocket import WebSocketClosedError, WebSocketHandler + +_io_loop = IOLoop.instance() + + +def _log_exception(): + """Log the most recent exception to ROS.""" + exc = traceback.format_exception(*sys.exc_info()) + RosbridgeWebSocket.node_handle.get_logger().error("".join(exc)) + + +def log_exceptions(f): + """Decorator for logging exceptions to ROS.""" + + @wraps(f) + def wrapper(*args, **kwargs): + try: + return f(*args, **kwargs) + except Exception: + _log_exception() + raise + + return wrapper + + +class IncomingQueue(threading.Thread): + """Decouples incoming messages from the Tornado thread. + + This mitigates cases where outgoing messages are blocked by incoming, + and vice versa. + """ + + def __init__(self, protocol): + threading.Thread.__init__(self) + self.daemon = True + self.queue = deque() + self.protocol = protocol + + self.cond = threading.Condition() + self._finished = False + + def finish(self): + """Clear the queue and do not accept further messages.""" + with self.cond: + self._finished = True + while len(self.queue) > 0: + self.queue.popleft() + self.cond.notify() + + def push(self, msg): + with self.cond: + self.queue.append(msg) + self.cond.notify() + + def run(self): + while True: + with self.cond: + if len(self.queue) == 0 and not self._finished: + self.cond.wait() + + if self._finished: + break + + msg = self.queue.popleft() + + self.protocol.incoming(msg) + + self.protocol.finish() + + +class RosbridgeWebSocket(WebSocketHandler): + clients_connected = 0 + use_compression = False + + # The following are passed on to RosbridgeProtocol + # defragmentation.py: + fragment_timeout = 600 # seconds + # protocol.py: + delay_between_messages = 0 # seconds + max_message_size = 10000000 # bytes + unregister_timeout = 10.0 # seconds + bson_only_mode = False + node_handle = None + + @log_exceptions + def open(self): + cls = self.__class__ + parameters = { + "fragment_timeout": cls.fragment_timeout, + "delay_between_messages": cls.delay_between_messages, + "max_message_size": cls.max_message_size, + "unregister_timeout": cls.unregister_timeout, + "bson_only_mode": cls.bson_only_mode, + } + try: + self.client_id = uuid.uuid4() + self.protocol = RosbridgeProtocol( + self.client_id, cls.node_handle, parameters=parameters + ) + self.incoming_queue = IncomingQueue(self.protocol) + self.incoming_queue.start() + self.protocol.outgoing = self.send_message + self.set_nodelay(True) + cls.clients_connected += 1 + if cls.client_manager: + cls.client_manager.add_client(self.client_id, self.request.remote_ip) + except Exception as exc: + cls.node_handle.get_logger().error( + f"Unable to accept incoming connection. Reason: {exc}" + ) + + cls.node_handle.get_logger().info( + f"Client connected. {cls.clients_connected} clients total." + ) + + @log_exceptions + def on_message(self, message): + if isinstance(message, bytes): + message = message.decode("utf-8") + self.incoming_queue.push(message) + + @log_exceptions + def on_close(self): + cls = self.__class__ + cls.clients_connected -= 1 + if cls.client_manager: + cls.client_manager.remove_client(self.client_id, self.request.remote_ip) + cls.node_handle.get_logger().info( + f"Client disconnected. {cls.clients_connected} clients total." + ) + self.incoming_queue.finish() + + def send_message(self, message, compression="none"): + if isinstance(message, bson.BSON): + binary = True + elif compression in ["cbor", "cbor-raw"]: + binary = True + else: + binary = False + + _io_loop.add_callback(partial(self.prewrite_message, message, binary)) + + async def prewrite_message(self, message, binary): + cls = self.__class__ + try: + await self.write_message(message, binary) + except WebSocketClosedError: + cls.node_handle.get_logger().warn( + "WebSocketClosedError: Tried to write to a closed websocket", + throttle_duration_sec=1.0, + ) + # If we end up here, a client has disconnected before its message callback(s) could be removed. + except StreamClosedError: + cls.node_handle.get_logger().warn( + "StreamClosedError: Tried to write to a closed stream", + throttle_duration_sec=1.0, + ) + except: # noqa: E722 # Will log and raise + _log_exception() + + @log_exceptions + def check_origin(self, origin): + return True + + @log_exceptions + def get_compression_options(self): + # If this method returns None (the default), compression will be disabled. + # If it returns a dict (even an empty one), it will be enabled. + cls = self.__class__ + + if not cls.use_compression: + return None + + return {} diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/advertise_service.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/advertise_service.test.py new file mode 100644 index 000000000..6097dc3f3 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/advertise_service.test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +import os +import sys +import unittest + +from rclpy.node import Node +from std_srvs.srv import SetBool +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestAdvertiseService(unittest.TestCase): + @websocket_test + async def test_two_concurrent_calls(self, node: Node, make_client): + ws_client = await make_client() + ws_client.sendJson( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": "/test_service", + } + ) + client = node.create_client(SetBool, "/test_service") + client.wait_for_service() + + requests_future, ws_client.message_handler = expect_messages( + 2, "WebSocket", node.get_logger() + ) + requests_future.add_done_callback(lambda _: node.executor.wake()) + + response1_future = client.call_async(SetBool.Request(data=True)) + response2_future = client.call_async(SetBool.Request(data=False)) + + requests = await requests_future + self.assertEqual(len(requests), 2) + + self.assertEqual(requests[0]["op"], "call_service") + self.assertEqual(requests[0]["service"], "/test_service") + self.assertEqual(requests[0]["args"], {"data": True}) + ws_client.sendJson( + { + "op": "service_response", + "service": "/test_service", + "values": {"success": True, "message": "Hello world 1"}, + "id": requests[0]["id"], + "result": True, + } + ) + + self.assertEqual(requests[1]["op"], "call_service") + self.assertEqual(requests[1]["service"], "/test_service") + self.assertEqual(requests[1]["args"], {"data": False}) + ws_client.sendJson( + { + "op": "service_response", + "service": "/test_service", + "values": {"success": True, "message": "Hello world 2"}, + "id": requests[1]["id"], + "result": True, + } + ) + + self.assertEqual( + await response1_future, SetBool.Response(success=True, message="Hello world 1") + ) + self.assertEqual( + await response2_future, SetBool.Response(success=True, message="Hello world 2") + ) + + node.destroy_client(client) diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/advertise_service_duplicate.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/advertise_service_duplicate.test.py new file mode 100644 index 000000000..466e44350 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/advertise_service_duplicate.test.py @@ -0,0 +1,99 @@ +import os +import sys +import unittest + +from rclpy.node import Node +from std_srvs.srv import SetBool +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, sleep, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestAdvertiseService(unittest.TestCase): + @websocket_test + async def test_double_advertise(self, node: Node, make_client): + ws_client1 = await make_client() + ws_client1.sendJson( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": "/test_service", + } + ) + client = node.create_client(SetBool, "/test_service") + client.wait_for_service() + + requests1_future, ws_client1.message_handler = expect_messages( + 1, "WebSocket 1", node.get_logger() + ) + requests1_future.add_done_callback(lambda _: node.executor.wake()) + + client.call_async(SetBool.Request(data=True)) + + requests1 = await requests1_future + self.assertEqual( + requests1, + [ + { + "op": "call_service", + "service": "/test_service", + "id": "service_request:/test_service:1", + "args": {"data": True}, + } + ], + ) + + ws_client1.sendClose() + + ws_client2 = await make_client() + ws_client2.sendJson( + { + "op": "advertise_service", + "type": "std_srvs/SetBool", + "service": "/test_service", + } + ) + + # wait for the server to handle the new advertisement + await sleep(node, 1) + + requests2_future, ws_client2.message_handler = expect_messages( + 1, "WebSocket 2", node.get_logger() + ) + requests2_future.add_done_callback(lambda _: node.executor.wake()) + + response2_future = client.call_async(SetBool.Request(data=False)) + + requests2 = await requests2_future + self.assertEqual( + requests2, + [ + { + "op": "call_service", + "id": "service_request:/test_service:1", + "service": "/test_service", + "args": {"data": False}, + } + ], + ) + + ws_client2.sendJson( + { + "op": "service_response", + "service": "/test_service", + "values": {"success": True, "message": "Hello world 2"}, + "id": "service_request:/test_service:1", + "result": True, + } + ) + + self.assertEqual( + await response2_future, SetBool.Response(success=True, message="Hello world 2") + ) diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/best_effort_publisher.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/best_effort_publisher.test.py new file mode 100644 index 000000000..2c84e6907 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/best_effort_publisher.test.py @@ -0,0 +1,54 @@ +import os +import sys +import unittest + +from rclpy.node import Node +from rclpy.qos import HistoryPolicy, QoSProfile, ReliabilityPolicy +from std_msgs.msg import String +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, sleep, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestBestEffortPublisher(unittest.TestCase): + @websocket_test + async def test_best_effort_publisher(self, node: Node, make_client): + qos = QoSProfile( + reliability=ReliabilityPolicy.BEST_EFFORT, + history=HistoryPolicy.SYSTEM_DEFAULT, + ) + pub_a = node.create_publisher(String, "/a_topic", qos_profile=qos) + + await sleep(node, 1) # wait for publisher to be set up + + ws_client1 = await make_client() + ws_client1.sendJson( + { + "op": "subscribe", + "topic": "/a_topic", + "type": "std_msgs/String", + } + ) + + await sleep(node, 1) # wait for subscriber to be set up + + pub_a.publish(String(data="hello")) + + ws1_completed_future, ws_client1.message_handler = expect_messages( + 1, "WebSocket 1", node.get_logger() + ) + ws1_completed_future.add_done_callback(lambda _: node.executor.wake()) + + self.assertEqual( + await ws1_completed_future, + [{"op": "publish", "topic": "/a_topic", "msg": {"data": "hello"}}], + ) + + node.destroy_publisher(pub_a) diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/call_service.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/call_service.test.py new file mode 100644 index 000000000..549b4cbb3 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/call_service.test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +import os +import sys +import unittest + +from rclpy.node import Node +from std_srvs.srv import SetBool +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestCallService(unittest.TestCase): + @websocket_test + async def test_one_call(self, node: Node, make_client): + def service_cb(req, res): + self.assertTrue(req.data) + res.success = True + res.message = "Hello, world!" + return res + + service = node.create_service(SetBool, "/test_service", service_cb) + + ws_client = await make_client() + responses_future, ws_client.message_handler = expect_messages( + 1, "WebSocket", node.get_logger() + ) + responses_future.add_done_callback(lambda _: node.executor.wake()) + + ws_client.sendJson( + { + "op": "call_service", + "type": "std_srvs/SetBool", + "service": "/test_service", + "args": {"data": True}, + } + ) + + responses = await responses_future + self.assertEqual(len(responses), 1) + self.assertEqual(responses[0]["op"], "service_response") + self.assertEqual(responses[0]["service"], "/test_service") + self.assertEqual(responses[0]["values"], {"success": True, "message": "Hello, world!"}) + self.assertEqual(responses[0]["result"], True) + + node.destroy_service(service) diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/common.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/common.py new file mode 100644 index 000000000..460f145d5 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/common.py @@ -0,0 +1,185 @@ +import functools +import json +from typing import Any, Awaitable, Callable + +import launch +import launch_ros +import rclpy +import rclpy.task +from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol +from rcl_interfaces.srv import GetParameters +from rclpy.executors import SingleThreadedExecutor +from rclpy.node import Node +from twisted.internet import reactor +from twisted.internet.endpoints import TCP4ClientEndpoint + + +class TestClientProtocol(WebSocketClientProtocol): + """ + Set message_handler to handle messages received from the server. + """ + + message_handler: Callable[[Any], None] + + def __init__(self, *args, **kwargs): + self.received = [] + self.connected_future = rclpy.task.Future() + self.message_handler = lambda _: None + super().__init__(*args, **kwargs) + + def onOpen(self): + self.connected_future.set_result(None) + + def sendJson(self, msg_dict, *, times=1): + msg = json.dumps(msg_dict).encode("utf-8") + for _ in range(times): + print(f"WebSocket client sent message: {msg}") + self.sendMessage(msg) + + def onMessage(self, payload, binary): + print(f"WebSocket client received message: {payload}") + self.message_handler(payload if binary else json.loads(payload)) + + +def _generate_node(): + try: + return launch_ros.actions.Node( + executable="rosbridge_websocket", + package="rosbridge_server", + parameters=[{"port": 0}], + ) + except TypeError: + # Deprecated keyword arg node_executable: https://github.com/ros2/launch_ros/pull/140 + return launch_ros.actions.Node( + node_executable="rosbridge_websocket", + package="rosbridge_server", + parameters=[{"port": 0}], + ) + + +try: + from launch_testing.actions import ReadyToTest + + def generate_test_description() -> launch.LaunchDescription: + """ + Generate a launch description that runs the websocket server. Re-export this from a test file and use add_launch_test() to run the test. + """ + return launch.LaunchDescription([_generate_node(), ReadyToTest()]) + +except ImportError: + + def generate_test_description(ready_fn) -> launch.LaunchDescription: + """ + Generate a launch description that runs the websocket server. Re-export this from a test file and use add_launch_test() to run the test. + """ + return launch.LaunchDescription( + [_generate_node(), launch.actions.OpaqueFunction(function=lambda context: ready_fn())] + ) + + +async def get_server_port(node: Node) -> int: + """ + Returns the port which the WebSocket server is running on + """ + client = node.create_client(GetParameters, "/rosbridge_websocket/get_parameters") + try: + if not client.wait_for_service(5): + raise RuntimeError("GetParameters service not available") + port_param = await client.call_async(GetParameters.Request(names=["actual_port"])) + return port_param.values[0].integer_value + finally: + node.destroy_client(client) + + +async def connect_to_server(node: Node) -> TestClientProtocol: + port = await get_server_port(node) + factory = WebSocketClientFactory("ws://127.0.0.1:" + str(port)) + factory.protocol = TestClientProtocol + + future = rclpy.task.Future() + future.add_done_callback(lambda _: node.executor.wake()) + + def connect(): + TCP4ClientEndpoint(reactor, "127.0.0.1", port).connect(factory).addCallback( + future.set_result + ) + + reactor.callFromThread(connect) + + protocol = await future + protocol.connected_future.add_done_callback(lambda _: node.executor.wake()) + await protocol.connected_future # wait for onOpen before proceeding + return protocol + + +def run_websocket_test( + node_name: str, + test_fn: Callable[[Node, Callable[[], Awaitable[TestClientProtocol]]], Awaitable[None]], +): + context = rclpy.Context() + rclpy.init(context=context) + executor = SingleThreadedExecutor(context=context) + node = rclpy.create_node(node_name, context=context) + executor.add_node(node) + + async def task(): + await test_fn(node, lambda: connect_to_server(node)) + reactor.callFromThread(reactor.stop) + + future = executor.create_task(task) + + reactor.callInThread(rclpy.spin_until_future_complete, node, future, executor) + reactor.run(installSignalHandlers=False) + + rclpy.shutdown(context=context) + node.destroy_node() + + +def sleep(node: Node, duration: float) -> Awaitable[None]: + """ + Async-compatible delay function based on a ROS timer. + """ + future = rclpy.task.Future() + + def callback(): + future.set_result(None) + timer.cancel() + node.destroy_timer(timer) + + timer = node.create_timer(duration, callback) + return future + + +def websocket_test(test_fn): + """ + Decorator for tests which use a ROS node and WebSocket server and client. + Multiple tests per file are not supported because the Twisted reactor cannot be run multiple times. + """ + + @functools.wraps(test_fn) + def run_test(self): + run_websocket_test(test_fn.__name__, lambda *args: test_fn(self, *args)) + + return run_test + + +def expect_messages(count: int, description: str, logger): + """ + Convenience function to create a Future and a message handler function which gathers results + into a list and waits for the list to have the expected number of items. + """ + future = rclpy.Future() + results = [] + + def handler(msg): + logger.info(f"Received message on {description}: {msg}") + results.append(msg) + if len(results) == count: + logger.info(f"Received all messages on {description}") + future.set_result(results) + elif len(results) > count: + raise AssertionError( + f"Received {len(results)} messages on {description} but expected {count}" + ) + + return future, handler diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/multiple_subscribers.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/multiple_subscribers.test.py new file mode 100644 index 000000000..58aaadb1b --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/multiple_subscribers.test.py @@ -0,0 +1,63 @@ +import os +import sys +import unittest + +from rclpy.node import Node +from std_msgs.msg import String +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, sleep, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestMultipleSubscribers(unittest.TestCase): + @websocket_test + async def test_multiple_subscribers(self, node: Node, make_client): + ws_client1 = await make_client() + ws_client1.sendJson( + { + "op": "subscribe", + "topic": "/a_topic", + "type": "std_msgs/String", + } + ) + + ws_client2 = await make_client() + ws_client2.sendJson( + { + "op": "subscribe", + "topic": "/a_topic", + "type": "std_msgs/String", + } + ) + + ws1_completed_future, ws_client1.message_handler = expect_messages( + 1, "WebSocket 1", node.get_logger() + ) + ws1_completed_future.add_done_callback(lambda _: node.executor.wake()) + ws2_completed_future, ws_client2.message_handler = expect_messages( + 1, "WebSocket 2", node.get_logger() + ) + ws2_completed_future.add_done_callback(lambda _: node.executor.wake()) + + pub_a = node.create_publisher(String, "/a_topic", 1) + + await sleep(node, 1) + + pub_a.publish(String(data="hello")) + + self.assertEqual( + await ws1_completed_future, + [{"op": "publish", "topic": "/a_topic", "msg": {"data": "hello"}}], + ) + self.assertEqual( + await ws2_completed_future, + [{"op": "publish", "topic": "/a_topic", "msg": {"data": "hello"}}], + ) + node.destroy_publisher(pub_a) diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/multiple_subscribers_raw.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/multiple_subscribers_raw.test.py new file mode 100644 index 000000000..a1f5c1f3e --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/multiple_subscribers_raw.test.py @@ -0,0 +1,50 @@ +import os +import sys +import unittest + +from rclpy.node import Node +from std_msgs.msg import String +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, sleep, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestMultipleSubscribers(unittest.TestCase): + @websocket_test + async def test_multiple_subscribers(self, node: Node, make_client): + sub_operation_json = { + "op": "subscribe", + "topic": "/a_topic", + "type": "std_msgs/String", + "compression": "cbor-raw", + } + ws_client1 = await make_client() + ws_client1.sendJson(sub_operation_json) + ws_client2 = await make_client() + ws_client2.sendJson(sub_operation_json) + + ws1_completed_future, ws_client1.message_handler = expect_messages( + 1, "WebSocket 1", node.get_logger() + ) + ws1_completed_future.add_done_callback(lambda _: node.executor.wake()) + ws2_completed_future, ws_client2.message_handler = expect_messages( + 1, "WebSocket 2", node.get_logger() + ) + ws2_completed_future.add_done_callback(lambda _: node.executor.wake()) + + pub_a = node.create_publisher(String, "/a_topic", 1) + + await sleep(node, 1) + pub_a.publish(String(data="hello")) + await sleep(node, 1) + + self.assertTrue(await ws1_completed_future) + self.assertTrue(await ws2_completed_future) + node.destroy_publisher(pub_a) diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/smoke.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/smoke.test.py new file mode 100644 index 000000000..2447ed424 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/smoke.test.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +import os +import sys +import unittest + +from rclpy.node import Node +from std_msgs.msg import String +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, sleep, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestWebsocketSmoke(unittest.TestCase): + @websocket_test + async def test_smoke(self, node: Node, make_client): + ws_client = await make_client() + # For consistency, the number of messages must not exceed the the protocol + # Subscriber queue_size. + NUM_MSGS = 10 + MSG_SIZE = 10 + A_TOPIC = "/a_topic" + B_TOPIC = "/b_topic" + A_STRING = "A" * MSG_SIZE + B_STRING = "B" * MSG_SIZE + WARMUP_DELAY = 1.0 # seconds + + sub_completed_future, sub_handler = expect_messages( + NUM_MSGS, "ROS subscriber", node.get_logger() + ) + ws_completed_future, ws_client.message_handler = expect_messages( + NUM_MSGS, "WebSocket", node.get_logger() + ) + ws_completed_future.add_done_callback(lambda _: node.executor.wake()) + + sub_a = node.create_subscription(String, A_TOPIC, sub_handler, NUM_MSGS) + pub_b = node.create_publisher(String, B_TOPIC, NUM_MSGS) + + ws_client.sendJson( + { + "op": "subscribe", + "topic": B_TOPIC, + "type": "std_msgs/String", + "queue_length": 0, # Test the roslib default. + } + ) + ws_client.sendJson( + { + "op": "advertise", + "topic": A_TOPIC, + "type": "std_msgs/String", + } + ) + + await sleep(node, WARMUP_DELAY) + + ws_client.sendJson( + { + "op": "publish", + "topic": A_TOPIC, + "msg": { + "data": A_STRING, + }, + }, + times=NUM_MSGS, + ) + + for _ in range(NUM_MSGS): + pub_b.publish(String(data=B_STRING)) + + ros_received = await sub_completed_future + ws_received = await ws_completed_future + + for msg in ws_received: + self.assertEqual("publish", msg["op"]) + self.assertEqual(B_TOPIC, msg["topic"]) + self.assertEqual(B_STRING, msg["msg"]["data"]) + self.assertEqual(NUM_MSGS, len(ws_received)) + + for msg in ros_received: + self.assertEqual(A_STRING, msg.data) + self.assertEqual(NUM_MSGS, len(ros_received)) + + node.destroy_subscription(sub_a) + node.destroy_publisher(pub_b) diff --git a/src/interface/rosbridge_suite/rosbridge_server/test/websocket/transient_local_publisher.test.py b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/transient_local_publisher.test.py new file mode 100644 index 000000000..d492350fb --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_server/test/websocket/transient_local_publisher.test.py @@ -0,0 +1,56 @@ +import os +import sys +import unittest + +from rclpy.node import Node +from rclpy.qos import DurabilityPolicy, HistoryPolicy, QoSProfile +from std_msgs.msg import String +from twisted.python import log + +sys.path.append(os.path.dirname(__file__)) # enable importing from common.py in this directory + +import common # noqa: E402 +from common import expect_messages, sleep, websocket_test # noqa: E402 + +log.startLogging(sys.stderr) + +generate_test_description = common.generate_test_description + + +class TestTransientLocalPublisher(unittest.TestCase): + @websocket_test + async def test_transient_local_publisher(self, node: Node, make_client): + qos = QoSProfile( + depth=1, + durability=DurabilityPolicy.TRANSIENT_LOCAL, + history=HistoryPolicy.KEEP_LAST, + ) + pub_a = node.create_publisher(String, "/a_topic", qos_profile=qos) + + await sleep(node, 1) + + pub_a.publish(String(data="hello")) + + await sleep(node, 1) + + for num in range(3): + ws_client = await make_client() + ws_client.sendJson( + { + "op": "subscribe", + "topic": "/a_topic", + "type": "std_msgs/String", + } + ) + + ws_completed_future, ws_client.message_handler = expect_messages( + 1, "WebSocket " + str(num), node.get_logger() + ) + ws_completed_future.add_done_callback(lambda _: node.executor.wake()) + + self.assertEqual( + await ws_completed_future, + [{"op": "publish", "topic": "/a_topic", "msg": {"data": "hello"}}], + ) + + node.destroy_publisher(pub_a) diff --git a/src/interface/rosbridge_suite/rosbridge_suite/CHANGELOG.rst b/src/interface/rosbridge_suite/rosbridge_suite/CHANGELOG.rst new file mode 100644 index 000000000..24d388ed1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_suite/CHANGELOG.rst @@ -0,0 +1,254 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosbridge_suite +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.3.1 (2022-10-21) +------------------ + +1.3.0 (2022-08-16) +------------------ + +1.2.0 (2022-05-20) +------------------ + +1.1.2 (2022-01-03) +------------------ + +1.1.1 (2021-12-09) +------------------ + +1.1.0 (2021-10-22) +------------------ + +1.0.8 (2021-08-26) +------------------ + +1.0.7 (2021-08-18) +------------------ +* Fix typos discovered by codespell (`#600 `_) +* Contributors: Christian Clauss + +1.0.6 (2021-08-17) +------------------ + +1.0.5 (2021-08-12) +------------------ + +1.0.4 (2021-08-11) +------------------ + +1.0.3 (2021-08-03) +------------------ + +1.0.2 (2019-09-24) +------------------ + +1.0.1 (2019-09-20) +------------------ + +1.0.0 (2019-09-19) +------------------ +* Port to ROS 2 + +0.11.3 (2019-08-07) +------------------- + +0.11.2 (2019-07-08) +------------------- + +0.11.1 (2019-05-08) +------------------- + +0.11.0 (2019-03-29) +------------------- + +0.10.2 (2019-03-04) +------------------- + +0.10.1 (2018-12-16) +------------------- + +0.10.0 (2018-12-14) +------------------- +* use package format 2, remove unnecessary dependencies (`#348 `_) +* Contributors: Dirk Thomas + +0.9.0 (2018-04-09) +------------------ + +0.8.6 (2017-12-08) +------------------ + +0.8.5 (2017-11-23) +------------------ + +0.8.4 (2017-10-16) +------------------ + +0.8.3 (2017-09-11) +------------------ + +0.8.2 (2017-09-11) +------------------ + +0.8.1 (2017-08-30) +------------------ + +0.8.0 (2017-08-30) +------------------ + +0.7.17 (2017-01-25) +------------------- + +0.7.16 (2016-08-15) +------------------- + +0.7.15 (2016-04-25) +------------------- +* changelog updated +* Contributors: Russell Toris + +0.7.14 (2016-02-11) +------------------- + +0.7.13 (2015-08-14) +------------------- + +0.7.12 (2015-04-07) +------------------- + +0.7.11 (2015-03-23) +------------------- + +0.7.10 (2015-02-25) +------------------- + +0.7.9 (2015-02-24) +------------------ + +0.7.8 (2015-01-16) +------------------ + +0.7.7 (2015-01-06) +------------------ + +0.7.6 (2014-12-26) +------------------ +* 0.7.5 +* update changelog +* 0.7.4 +* changelog updated +* 0.7.3 +* changelog updated +* 0.7.2 +* changelog updated +* 0.7.1 +* update changelog +* 0.7.0 +* changelog updated +* Contributors: Jihoon Lee, Russell Toris + +0.7.5 (2014-12-26) +------------------ + +0.7.4 (2014-12-16) +------------------ + +0.7.3 (2014-12-15) +------------------ + +0.7.2 (2014-12-15) +------------------ +* 0.7.1 +* update changelog +* Contributors: Jihoon Lee + +0.7.1 (2014-12-09) +------------------ + +0.7.0 (2014-12-02) +------------------ + +0.6.8 (2014-11-05) +------------------ + +0.6.7 (2014-10-22) +------------------ +* updated package manifests +* Contributors: Russell Toris + +0.6.6 (2014-10-21) +------------------ + +0.6.5 (2014-10-14) +------------------ +* 0.6.4 +* update changelog +* 0.6.3 +* update change log +* Contributors: Jihoon Lee + +0.6.4 (2014-10-08) +------------------ + +0.6.3 (2014-10-07) +------------------ + +0.6.2 (2014-10-06) +------------------ + +0.6.1 (2014-09-01) +------------------ + +0.6.0 (2014-05-23) +------------------ + +0.5.4 (2014-04-17) +------------------ + +0.5.3 (2014-03-28) +------------------ + +0.5.2 (2014-03-14) +------------------ + +0.5.1 (2013-10-31) +------------------ + +0.5.0 (2013-07-17) +------------------ +* 0.5.0 preparation for hydro release +* Contributors: Jihoon Lee + +0.4.4 (2013-04-08) +------------------ +* adding russl and myself as maintainer. adding build_tool depend +* Contributors: Jihoon Lee + +0.4.3 (2013-04-03 08:24) +------------------------ +* adding CMake list for meta pkg +* Contributors: Jihoon Lee + +0.4.2 (2013-04-03 08:12) +------------------------ + +0.4.1 (2013-03-07) +------------------ + +0.4.0 (2013-03-05) +------------------ +* cleaning up meta package +* Catkinizing rosbridge_library and server. +* Collapse directory structure. +* Removed print statements and also made sure to cast any tuples to lists. +* Removed the pypng dependency and finalised PIL dependency +* Use python imaging library to encode PNG instead of pypng +* Added the ujson library, modified cmakelists to install ujson to the + user python directory. +* Fixed an inconsequential elif bug. +* Refactored to use simplejson if the package is installed. +* Added simplejson library and moved the location of the libraries. +* Temporary commit adding profiling messages. something is going awry. +* Renamed rosbridge stack to rosbridge_suite +* Contributors: Austin Hendrix, Brandon Alexander, Jihoon Lee, jon diff --git a/src/interface/rosbridge_suite/rosbridge_suite/CMakeLists.txt b/src/interface/rosbridge_suite/rosbridge_suite/CMakeLists.txt new file mode 100644 index 000000000..1b638c379 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_suite/CMakeLists.txt @@ -0,0 +1,4 @@ +cmake_minimum_required(VERSION 3.5) +project(rosbridge_suite NONE) +find_package(ament_cmake_core REQUIRED) +ament_package() diff --git a/src/interface/rosbridge_suite/rosbridge_suite/package.xml b/src/interface/rosbridge_suite/rosbridge_suite/package.xml new file mode 100644 index 000000000..e27213d29 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_suite/package.xml @@ -0,0 +1,33 @@ + + + rosbridge_suite + 1.3.1 + + Rosbridge provides a JSON API to ROS functionality for non-ROS programs. + There are a variety of front ends that interface with rosbridge, including + a WebSocket server for web browsers to interact with. + + Rosbridge_suite is a meta-package containing rosbridge, various front end + packages for rosbridge like a WebSocket package, and helper packages. + + + BSD + + http://ros.org/wiki/rosbridge_suite + https://github.com/RobotWebTools/rosbridge_suite/issues + https://github.com/RobotWebTools/rosbridge_suite + + Jonathan Mace + Jihoon Lee + Foxglove + + ament_cmake_core + + rosbridge_library + rosbridge_server + rosapi + + + ament_cmake + + diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/CHANGELOG.rst b/src/interface/rosbridge_suite/rosbridge_test_msgs/CHANGELOG.rst new file mode 100644 index 000000000..c3a3b7e90 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/CHANGELOG.rst @@ -0,0 +1,23 @@ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Changelog for package rosbridge_test_msgs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1.3.1 (2022-10-21) +------------------ + +1.3.0 (2022-08-16) +------------------ + +1.2.0 (2022-05-20) +------------------ + +1.1.2 (2022-01-03) +------------------ + +1.1.1 (2021-12-09) +------------------ + +1.1.0 (2021-10-22) +------------------ +* Move msg/srv from rosapi and rosbridge_library into separate packages; enable Rolling in CI (`#665 `_) +* Contributors: Jacob Bandes-Storch diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/CMakeLists.txt b/src/interface/rosbridge_suite/rosbridge_test_msgs/CMakeLists.txt new file mode 100644 index 000000000..414990004 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.5) +project(rosbridge_test_msgs) + +find_package(ament_cmake_core REQUIRED) +find_package(ament_cmake_python REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(rosidl_default_generators REQUIRED) +find_package(std_msgs REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + msg/Num.msg + msg/TestChar.msg + msg/TestDurationArray.msg + msg/TestHeaderArray.msg + msg/TestHeader.msg + msg/TestHeaderTwo.msg + msg/TestTimeArray.msg + msg/TestUInt8.msg + msg/TestUInt8FixedSizeArray16.msg + msg/TestFloat32Array.msg + msg/TestFloat32BoundedArray.msg + srv/AddTwoInts.srv + srv/SendBytes.srv + srv/TestArrayRequest.srv + srv/TestEmpty.srv + srv/TestMultipleRequestFields.srv + srv/TestMultipleResponseFields.srv + srv/TestNestedService.srv + srv/TestRequestAndResponse.srv + srv/TestRequestOnly.srv + srv/TestResponseOnly.srv + DEPENDENCIES builtin_interfaces geometry_msgs std_msgs +) + +ament_export_dependencies(rosidl_default_runtime) + +ament_package() diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/Num.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/Num.msg new file mode 100644 index 000000000..980698192 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/Num.msg @@ -0,0 +1 @@ +int64 num diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestChar.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestChar.msg new file mode 100644 index 000000000..2ca013ff2 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestChar.msg @@ -0,0 +1 @@ +char[] data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestDurationArray.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestDurationArray.msg new file mode 100644 index 000000000..79581a2f1 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestDurationArray.msg @@ -0,0 +1 @@ +builtin_interfaces/Duration[] durations diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestFloat32Array.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestFloat32Array.msg new file mode 100644 index 000000000..99f5e0fb3 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestFloat32Array.msg @@ -0,0 +1 @@ +float32[] data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestFloat32BoundedArray.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestFloat32BoundedArray.msg new file mode 100644 index 000000000..980e4f985 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestFloat32BoundedArray.msg @@ -0,0 +1 @@ +float32[16] data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeader.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeader.msg new file mode 100644 index 000000000..e3dee5e9c --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeader.msg @@ -0,0 +1 @@ +std_msgs/Header header diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeaderArray.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeaderArray.msg new file mode 100644 index 000000000..0b6a85894 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeaderArray.msg @@ -0,0 +1 @@ +std_msgs/Header[] header diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeaderTwo.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeaderTwo.msg new file mode 100644 index 000000000..e3dee5e9c --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestHeaderTwo.msg @@ -0,0 +1 @@ +std_msgs/Header header diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestTimeArray.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestTimeArray.msg new file mode 100644 index 000000000..a805a061a --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestTimeArray.msg @@ -0,0 +1 @@ +builtin_interfaces/Time[] times diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestUInt8.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestUInt8.msg new file mode 100644 index 000000000..dd2331bbe --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestUInt8.msg @@ -0,0 +1 @@ +uint8[] data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestUInt8FixedSizeArray16.msg b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestUInt8FixedSizeArray16.msg new file mode 100644 index 000000000..637d12d94 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/msg/TestUInt8FixedSizeArray16.msg @@ -0,0 +1 @@ +uint8[16] data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/package.xml b/src/interface/rosbridge_suite/rosbridge_test_msgs/package.xml new file mode 100644 index 000000000..24f619de5 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/package.xml @@ -0,0 +1,52 @@ + + + rosbridge_test_msgs + 1.3.1 + + Message and service definitions used in internal tests for rosbridge packages. + + + BSD + + http://ros.org/wiki/rosbridge_library + https://github.com/RobotWebTools/rosbridge_suite/issues + https://github.com/RobotWebTools/rosbridge_suite + + Jonathan Mace + Jihoon Lee + Foxglove + + ament_cmake + + builtin_interfaces + std_msgs + geometry_msgs + rosidl_default_generators + + builtin_interfaces + rclpy + std_msgs + geometry_msgs + rosidl_default_runtime + + actionlib_msgs + ament_cmake_pytest + builtin_interfaces + diagnostic_msgs + example_interfaces + geometry_msgs + nav_msgs + sensor_msgs + std_msgs + std_srvs + stereo_msgs + tf2_msgs + trajectory_msgs + visualization_msgs + + rosidl_interface_packages + + + ament_cmake + + diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/AddTwoInts.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/AddTwoInts.srv new file mode 100644 index 000000000..3a68808ee --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/AddTwoInts.srv @@ -0,0 +1,4 @@ +int64 a +int64 b +--- +int64 sum diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/SendBytes.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/SendBytes.srv new file mode 100644 index 000000000..a767405e3 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/SendBytes.srv @@ -0,0 +1,3 @@ +int64 count +--- +string data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestArrayRequest.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestArrayRequest.srv new file mode 100644 index 000000000..25dcfcfe7 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestArrayRequest.srv @@ -0,0 +1,2 @@ +int32[] int_values +--- diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestEmpty.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestEmpty.srv new file mode 100644 index 000000000..ed97d539c --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestEmpty.srv @@ -0,0 +1 @@ +--- diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestMultipleRequestFields.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestMultipleRequestFields.srv new file mode 100644 index 000000000..4104e19ff --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestMultipleRequestFields.srv @@ -0,0 +1,5 @@ +int32 int_value +float32 float_value +string string +bool bool_value +--- diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestMultipleResponseFields.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestMultipleResponseFields.srv new file mode 100644 index 000000000..a0f6f05e9 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestMultipleResponseFields.srv @@ -0,0 +1,5 @@ +--- +int32 int_value +float32 float_value +string string +bool bool_value diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestNestedService.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestNestedService.srv new file mode 100644 index 000000000..860dc1be8 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestNestedService.srv @@ -0,0 +1,5 @@ +#request definition +geometry_msgs/Pose pose +--- +#response definition +std_msgs/Float64 data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestRequestAndResponse.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestRequestAndResponse.srv new file mode 100644 index 000000000..71badf763 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestRequestAndResponse.srv @@ -0,0 +1,3 @@ +int32 data +--- +int32 data diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestRequestOnly.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestRequestOnly.srv new file mode 100644 index 000000000..1b25cca17 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestRequestOnly.srv @@ -0,0 +1,2 @@ +int32 data +--- diff --git a/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestResponseOnly.srv b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestResponseOnly.srv new file mode 100644 index 000000000..91b71a0c7 --- /dev/null +++ b/src/interface/rosbridge_suite/rosbridge_test_msgs/srv/TestResponseOnly.srv @@ -0,0 +1,2 @@ +--- +int32 data diff --git a/src/interface/rosbridge_suite/setup.cfg b/src/interface/rosbridge_suite/setup.cfg new file mode 100644 index 000000000..b603296fe --- /dev/null +++ b/src/interface/rosbridge_suite/setup.cfg @@ -0,0 +1,13 @@ +[codespell] +ignore-words-list = miror + +[flake8] +count = True +max-complexity = 36 +max-line-length = 217 +ignore = E203,W503 +show-source = True +statistics = True + +[isort] +profile = black diff --git a/src/interface/sim_bridge/sim_bridge/sim_bridge_node.py b/src/interface/sim_bridge/sim_bridge/sim_bridge_node.py index ffcfbb2e0..51cfea50e 100755 --- a/src/interface/sim_bridge/sim_bridge/sim_bridge_node.py +++ b/src/interface/sim_bridge/sim_bridge/sim_bridge_node.py @@ -151,7 +151,7 @@ def front_lidar_cb(self, data: carla.LidarMeasurement): # Taken from carla_ros_bridge's "lidar.py". WSH. header = Header( stamp=self.get_clock().now().to_msg(), - frame_id='lidar_front' + frame_id='lidar_right' ) lidar_data = np.fromstring( @@ -291,7 +291,7 @@ def sem_lidar_cb(self, data: carla.SemanticLidarMeasurement): # Taken from carla_ros_bridge's "lidar.py". WSH. header = Header( stamp=self.get_clock().now().to_msg(), - frame_id='lidar_front' + frame_id='lidar_right' ) lidar_data = np.fromstring( @@ -503,7 +503,7 @@ def __init__(self): self.front_lidar_pub = self.create_publisher( PointCloud2, - '/lidar_front/points_raw', + '/lidar_right/points_raw', 1 ) @@ -515,7 +515,7 @@ def __init__(self): self.rear_lidar_pub = self.create_publisher( PointCloud2, - '/lidar_rear/points_raw', + '/lidar_left/points_raw', 1 ) diff --git a/src/interface/throttle_control/package.xml b/src/interface/throttle_control/package.xml new file mode 100755 index 000000000..288bb9a2c --- /dev/null +++ b/src/interface/throttle_control/package.xml @@ -0,0 +1,16 @@ + + + + throttle_control + 1.0.0 + Node to send throttle commands as serial messages + Jai Peris + MIT + + ament_lint_auto + ament_lint_common + + + ament_python + + diff --git a/src/interface/throttle_control/resource/throttle_control b/src/interface/throttle_control/resource/throttle_control new file mode 100755 index 000000000..e69de29bb diff --git a/src/interface/throttle_control/setup.cfg b/src/interface/throttle_control/setup.cfg new file mode 100755 index 000000000..42716a90e --- /dev/null +++ b/src/interface/throttle_control/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/throttle_control +[install] +install-scripts=$base/lib/throttle_control diff --git a/src/perception/dynamic_grid/setup.py b/src/interface/throttle_control/setup.py similarity index 81% rename from src/perception/dynamic_grid/setup.py rename to src/interface/throttle_control/setup.py index a19d94682..139d58c84 100755 --- a/src/perception/dynamic_grid/setup.py +++ b/src/interface/throttle_control/setup.py @@ -2,7 +2,7 @@ from glob import glob import os -package_name = 'dynamic_grid' +package_name = 'throttle_control' setup( name=package_name, @@ -17,13 +17,13 @@ install_requires=['setuptools'], zip_safe=True, maintainer='main', - maintainer_email='will.heitman@utdallas.edu', + maintainer_email='jai.peris@utdallas.edu', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ - 'dynamic_grid_node = dynamic_grid.dynamic_grid_node:main', + 'throttle_node = throttle_control.throttle_node:main', ], }, ) diff --git a/src/interface/throttle_control/throttle_control/__init__.py b/src/interface/throttle_control/throttle_control/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/interface/throttle_control/throttle_control/throttle_node.py b/src/interface/throttle_control/throttle_control/throttle_node.py new file mode 100644 index 000000000..7073daaf6 --- /dev/null +++ b/src/interface/throttle_control/throttle_control/throttle_node.py @@ -0,0 +1,59 @@ +import numpy as np +import pickle +import sys +import os +import math +import serial +import io +#from shadowcasting import ShadowCaster + +# Message definitions +from carla_msgs.msg import CarlaEgoVehicleControl +from rosgraph_msgs.msg import Clock + +import rclpy +from rclpy.node import Node +import ros2_numpy as rnp +from std_msgs.msg import String + + + + +class throttle_node(Node): + def __init__(self): + super().__init__('throttle_node') + self.get_logger().info('#####################################################################################') + self.carla_sub = self.create_subscription(CarlaEgoVehicleControl, '/carla/hero/vehicle_control_cmd', self.send_message, 10) + + test_msg = CarlaEgoVehicleControl() + test_msg.throttle = 0.5 + + self.send_message(test_msg) + self.send_message(test_msg) + + + def send_message(self, msg: CarlaEgoVehicleControl): + self.get_logger().info(f"Received throttle with value {msg.throttle}") + + throttle = msg.throttle + with serial.Serial('/dev/ttyACM0', 115200) as ser: + # cmd = f"t{throttle}".encode('utf-16be') + sio = io.TextIOWrapper(io.BufferedRWPair(ser, ser)) + sio.write(u't0.5\n') + sio.flush() + hello = sio.readline() + print(hello) + + + + +def main(args=None): + rclpy.init(args=args) + throttle = throttle_node() + rclpy.spin(throttle) + #self.get_logger().info('#####################################################################################') + throttle.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/src/mapping/helper_scripts/grid_divider_exe.py b/src/mapping/helper_scripts/grid_divider_exe.py deleted file mode 100755 index dc8ee94f2..000000000 --- a/src/mapping/helper_scripts/grid_divider_exe.py +++ /dev/null @@ -1,216 +0,0 @@ -#!/usr/bin/python3 - -""" -This is a quick-and-dirty script that accepts a single unfiltered PCD file, -divides it into uniform cells, and then removes ground points from each cell. - -With the FORM_COMBINED_MAP flag, the script will recombine the filtered cells -to produce a single filtered map. This is only needed if you wish to see the -full result instead of seeing individual cells. You can convert the combined -result from .las to .pcd using the "pdal translate" command. PDAL messes up -pcd headers during conversion, so compare the result header to a working pcd -file's to fix. You just need to change the sizes from 8 to 4 and the X Y Z to -x y z. - -Remember that pcd files can be visualized using the pcl_viewer tool. - -Script usage: grid_divider_exe.py [input.pcd] [cell size] -""" - -import getopt, sys -import numpy as np -from tqdm import tqdm -import math -import os, pathlib -import json -import subprocess - -MIN_FILTER_SIZE = 500 # Number of points that cell must contain for it to be filtered -FORM_COMBINED_MAP = True - -PIPELINE_STR = """ -{ - "pipeline":[ - { - "type":"readers.las", - "filename":"tmp.las" - }, - { - "type":"filters.assign", - "assignment":"Classification[:]=0" - }, - { - "type":"filters.elm" - }, - { - "type":"filters.outlier" - }, - { - "type":"filters.smrf", - "ignore":"Classification[7:7]", - "slope":0.2, - "window":16, - "threshold":0.55, - "scalar":1.2 - }, - { - "type":"filters.range", - "limits":"Classification![2:2]" - }, - { - "type":"filters.range", - "limits":"Classification![7:7]" - }, - { - "type":"writers.pcd", - "filename":"res.pcd", - "order": "X,Y,Z", - "keep_unspecified": false - } - ] -} -""" -pipeline_json = json.loads(PIPELINE_STR) - -def main(argv): - if len(sys.argv) < 3: - print("Usage: {} inputfile.pcd cellSize".format(sys.argv[0])) - sys.exit(2) - filename = sys.argv[1] - cellSize = int(sys.argv[2]) - - print("Reading from file. This might take a while...") - points = np.loadtxt(filename, skiprows=11) - min_x = np.amin(points[:, 0]) - min_y = np.amin(points[:, 1]) - max_x = np.amax(points[:, 0]) - max_y = np.amax(points[:, 1]) - print("Loaded {}x{} PCD with min ({},{})".format(max_x-min_x, max_y-min_y, min_x, min_y)) - - # Starting with the min corner (min x, min y) - cellCorner = [min_x, min_y] - cell_i = 0 - rejected_count = 0 - cell_width = math.ceil(((max_x-min_x)/cellSize)) - for i in tqdm(range(cell_width)): # Cell columns (x) - points_in_column_mask = (points[:,0]>=cellCorner[0]) & \ - (points[:,0]= cellCorner, x < cellCorner+cellSize - # y >= cellCorner[1], y < cellCorner+cellSize - # move points into separate array, save to A_B.pcd - points_in_cell_mask = (points_in_column[:,1]>=cellCorner[1]) & \ - (points_in_column[:,1] MIN_FILTER_SIZE: - # print(points_in_cell.size) - removeGroundPointsWithPDAL("{}_{}.pcd".format(cell_i, cell_j)) - - fixfile = open("{}_{}.pcd".format(cell_i, cell_j),'r') - lines = fixfile.readlines() - fixfile.close() - fixfile = open("{}_{}.pcd".format(cell_i, cell_j),'w') - header = """# .PCD v0.7 - Point Cloud Data file format -VERSION 0.7 -FIELDS x y z -SIZE 4 4 4 -TYPE F F F -COUNT 1 1 1 -WIDTH {} -HEIGHT 1 -VIEWPOINT 0 0 0 1 0 0 0 -POINTS {} -DATA ascii""".format(len(lines)-10,len(lines)-10) - fixfile.write(header+"\n") - fixfile.writelines(lines[10:]) - fixfile.close() - else: - rejected_count += 1 - - cell_j += 1 - cellCorner[1] += cellSize - cell_i += 1 - cellCorner[0] += cellSize - print("Generated {}x{} grid, with {}/{} cells unfiltered, from ({},{}) to ({},{})".format(cell_i, cell_j, rejected_count, cell_i*cell_j, min_x, min_y, max_x, max_y)) - - if FORM_COMBINED_MAP: - formCombinedMap() - - -def formCombinedMap(): - # Get all pcd files in cwd containing just numbers and an underscore - files = [f for f in os.listdir('.') if (os.path.isfile(f) and f[-4:]=='.pcd' and f[0].isnumeric())] - # print(files) - - # Convert to LAS format for PDAL - lasfiles = [] - for file in files: - lasfile = file.split('.')[0]+'.las' - bashCommand = "pdal translate {} {}".format(file, lasfile) - process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE) - output, error = process.communicate() - lasfiles.append(lasfile) - - # print(lasfiles) - - lasfiles.append("combined.las") - file_pipeline = json.dumps(lasfiles) - # print(file_pipeline) - with open("combined_pipeline.json", 'w') as file: - file.write(file_pipeline) - - # Apply ground smoothing pipeline, which overwrites file with filtered version - bashCommand = "pdal pipeline combined_pipeline.json" - process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE) - output, error = process.communicate() - -def removeGroundPointsWithPDAL(filename): - # Convert to LAS format for PDAL - bashCommand = "pdal translate {} tmp.las".format(filename) - process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE) - output, error = process.communicate() - - # Write to pipeline.json - pipeline_json["pipeline"][7]["filename"] = filename - with open("pipeline.json", 'w') as file: - json.dump(pipeline_json, file) - - # print(pipeline_json) - - # Apply ground smoothing pipeline, which overwrites file with filtered version - bashCommand = "pdal pipeline pipeline.json" - process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE) - output, error = process.communicate() - - -def saveToPcd(point_array, filename): - header = generateHeader(point_array) - np.savetxt(filename, point_array, header=header, fmt="%f", comments="") - return - -def generateHeader(point_array): - # The awful indention is necessary for proper string formatting... - return """# .PCD v0.7 - Point Cloud Data file format -VERSION 0.7 -FIELDS x y z -SIZE 4 4 4 -TYPE F F F -COUNT 1 1 1 -WIDTH {} -HEIGHT 1 -VIEWPOINT 0 0 0 1 0 0 0 -POINTS {} -DATA ascii""".format(np.shape(point_array)[0],np.shape(point_array)[0]) - -if __name__ == "__main__": - main(sys.argv) - -# Read PCD file -# Convert points into numpy array -# Find min x, min y, max x, max y -# with open() \ No newline at end of file diff --git a/src/mapping/lio_sam/.github/stale.yml b/src/mapping/lio_sam/.github/stale.yml deleted file mode 100755 index 2a02cae4e..000000000 --- a/src/mapping/lio_sam/.github/stale.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 14 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 1 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security -# Label to use when marking an issue as stale -staleLabel: stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/src/mapping/lio_sam/CMakeLists.txt b/src/mapping/lio_sam/CMakeLists.txt deleted file mode 100755 index d17046b59..000000000 --- a/src/mapping/lio_sam/CMakeLists.txt +++ /dev/null @@ -1,103 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(lio_sam) - -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE Release) -endif() - -# find dependencies -find_package(ament_cmake REQUIRED) -find_package(rosidl_default_generators REQUIRED) -find_package(rclcpp REQUIRED) -find_package(rclpy REQUIRED) -find_package(cv_bridge REQUIRED) -find_package(std_msgs REQUIRED) -find_package(sensor_msgs REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(std_srvs REQUIRED) -find_package(nav_msgs REQUIRED) -find_package(visualization_msgs REQUIRED) -find_package(tf2 REQUIRED) -find_package(tf2_geometry_msgs REQUIRED) -find_package(tf2_sensor_msgs REQUIRED) -find_package(tf2_eigen REQUIRED) -find_package(tf2_ros REQUIRED) -find_package(OpenCV REQUIRED) -find_package(PCL REQUIRED) -find_package(GTSAM REQUIRED) -find_package(Eigen REQUIRED) - -include_directories( - include/lio_sam -) - -rosidl_generate_interfaces(${PROJECT_NAME} "msg/CloudInfo.msg" DEPENDENCIES std_msgs sensor_msgs) - -add_executable(${PROJECT_NAME}_featureExtraction src/featureExtraction.cpp) -ament_target_dependencies(${PROJECT_NAME}_featureExtraction rclcpp rclpy std_msgs sensor_msgs geometry_msgs nav_msgs tf2 tf2_ros tf2_eigen tf2_sensor_msgs tf2_geometry_msgs OpenCV PCL) -rosidl_target_interfaces(${PROJECT_NAME}_featureExtraction ${PROJECT_NAME} "rosidl_typesupport_cpp") - -add_executable(${PROJECT_NAME}_imageProjection src/imageProjection.cpp) -ament_target_dependencies(${PROJECT_NAME}_imageProjection rclcpp rclpy std_msgs sensor_msgs geometry_msgs nav_msgs tf2 tf2_ros tf2_eigen tf2_sensor_msgs tf2_geometry_msgs OpenCV PCL) -rosidl_target_interfaces(${PROJECT_NAME}_imageProjection ${PROJECT_NAME} "rosidl_typesupport_cpp") - -add_executable(${PROJECT_NAME}_imuPreintegration src/imuPreintegration.cpp) -ament_target_dependencies(${PROJECT_NAME}_imuPreintegration rclcpp rclpy std_msgs sensor_msgs geometry_msgs nav_msgs tf2 tf2_ros tf2_eigen tf2_sensor_msgs tf2_geometry_msgs OpenCV PCL GTSAM Eigen) -target_link_libraries(${PROJECT_NAME}_imuPreintegration gtsam) -rosidl_target_interfaces(${PROJECT_NAME}_imuPreintegration ${PROJECT_NAME} "rosidl_typesupport_cpp") - -add_executable(${PROJECT_NAME}_mapOptimization src/mapOptmization.cpp) -ament_target_dependencies(${PROJECT_NAME}_mapOptimization rclcpp rclpy std_msgs sensor_msgs std_srvs geometry_msgs nav_msgs visualization_msgs tf2 tf2_ros tf2_eigen tf2_sensor_msgs tf2_geometry_msgs OpenCV PCL GTSAM) -target_link_libraries(${PROJECT_NAME}_mapOptimization gtsam) -rosidl_target_interfaces(${PROJECT_NAME}_mapOptimization ${PROJECT_NAME} "rosidl_typesupport_cpp") - -install( - DIRECTORY launch - DESTINATION share/${PROJECT_NAME}/ -) - -install( - DIRECTORY config - DESTINATION share/${PROJECT_NAME}/ -) - -install( - TARGETS ${PROJECT_NAME}_imageProjection - DESTINATION lib/${PROJECT_NAME} -) - -install( - TARGETS ${PROJECT_NAME}_imuPreintegration - DESTINATION lib/${PROJECT_NAME} -) - -install( - TARGETS ${PROJECT_NAME}_featureExtraction - DESTINATION lib/${PROJECT_NAME} -) - -install( - TARGETS ${PROJECT_NAME}_mapOptimization - DESTINATION lib/${PROJECT_NAME} -) - -install( - DIRECTORY "include/" - DESTINATION include -) - -ament_export_include_directories(include) - -if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - # the following line skips the linter which checks for copyrights - # uncomment the line when a copyright and license is not present in all source files - #set(ament_cmake_copyright_FOUND TRUE) - # the following line skips cpplint (only works in a git repo) - # uncomment the line when this package is not in a git repo - #set(ament_cmake_cpplint_FOUND TRUE) - ament_lint_auto_find_test_dependencies() -endif() - -ament_package() - diff --git a/src/mapping/lio_sam/LICENSE b/src/mapping/lio_sam/LICENSE deleted file mode 100755 index d4c5d8dbd..000000000 --- a/src/mapping/lio_sam/LICENSE +++ /dev/null @@ -1,30 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2020, Tixiao Shan -Copyright (c) 2021, Christoph Gruber -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/mapping/lio_sam/README.md b/src/mapping/lio_sam/README.md deleted file mode 100755 index 7db3f72be..000000000 --- a/src/mapping/lio_sam/README.md +++ /dev/null @@ -1,231 +0,0 @@ -# LIO-SAM - -**A real-time lidar-inertial odometry package. We strongly recommend the users read this document thoroughly and test the package with the provided dataset first. A video of the demonstration of the method can be found on [YouTube](https://www.youtube.com/watch?v=A0H8CoORZJU).** - -

        - drawing -

        - -

        - drawing - drawing - drawing - drawing -

        - -## Menu - - - [**System architecture**](#system-architecture) - - - [**Notes on ROS2 branch**](#notes-on-ros2-branch) - - - [**Package dependency**](#dependency) - - - [**Package install**](#install) - - - [**Prepare lidar data**](#prepare-lidar-data) (must read) - - - [**Prepare IMU data**](#prepare-imu-data) (must read) - - - [**Sample datasets**](#sample-datasets) - - - [**Run the package**](#run-the-package) - - - [**Other notes**](#other-notes) - - - [**Issues**](#issues) - - - [**Paper**](#paper) - - - [**TODO**](#todo) - - - [**Related Package**](#related-package) - - - [**Acknowledgement**](#acknowledgement) - -## System architecture - -

        - drawing -

        - -We design a system that maintains two graphs and runs up to 10x faster than real-time. - - The factor graph in "mapOptimization.cpp" optimizes lidar odometry factor and GPS factor. This factor graph is maintained consistently throughout the whole test. - - The factor graph in "imuPreintegration.cpp" optimizes IMU and lidar odometry factor and estimates IMU bias. This factor graph is reset periodically and guarantees real-time odometry estimation at IMU frequency. - -## Notes on ROS2 branch - -There are some features of the original ROS1 version that are currently missing in this ROS2 version, namely: -- The service for saving maps -- Testing with Velodyne lidars and Microstrain IMUs -- A launch file for the navsat module/GPS factor -- The rviz2 configuration misses many elements - -This branch was tested with an Ouster lidar and a Xsens IMU using the following ROS2 drivers: -- [ros2_ouster_drivers](https://github.com/ros-drivers/ros2_ouster_drivers) -- [bluespace_ai_xsens_ros_mti_driver](https://github.com/bluespace-ai/bluespace_ai_xsens_ros_mti_driver) - -In these tests, the IMU was mounted on the bottom of the lidar such that their x-axes pointed in the same direction. The parameters `extrinsicRot` and `extrinsicRPY` in `params.yaml` correspond to this constellation. - -## Dependencies - -- [ROS2](https://docs.ros.org/en/foxy/Installation.html) (tested with Foxy on Ubuntu 20.04) - ``` - sudo apt install ros-foxy-perception-pcl \ - ros-foxy-pcl-msgs \ - ros-foxy-vision-opencv \ - ros-foxy-xacro - ``` -- [gtsam](https://github.com/borglab/gtsam/releases) (Georgia Tech Smoothing and Mapping library) - ``` - # Add GTSAM-PPA - sudo add-apt-repository ppa:borglab/gtsam-release-4.0 - sudo apt install libgtsam-dev libgtsam-unstable-dev - ``` - -## Install - -Use the following commands to download and compile the package. - - ``` - cd ~/ros2_ws/src - git clone https://github.com/TixiaoShan/LIO-SAM.git - cd lio-sam - git checkout ros2 - cd .. - colcon build - ``` - -## Prepare lidar data - -The user needs to prepare the point cloud data in the correct format for cloud deskewing, which is mainly done in "imageProjection.cpp". The two requirements are: - - **Provide point time stamp**. LIO-SAM uses IMU data to perform point cloud deskew. Thus, the relative point time in a scan needs to be known. The up-to-date Velodyne ROS driver should output this information directly. Here, we assume the point time channel is called "time." The definition of the point type is located at the top of the "imageProjection.cpp." "deskewPoint()" function utilizes this relative time to obtain the transformation of this point relative to the beginning of the scan. When the lidar rotates at 10Hz, the timestamp of a point should vary between 0 and 0.1 seconds. If you are using other lidar sensors, you may need to change the name of this time channel and make sure that it is the relative time in a scan. - - **Provide point ring number**. LIO-SAM uses this information to organize the point correctly in a matrix. The ring number indicates which channel of the sensor that this point belongs to. The definition of the point type is located at the top of "imageProjection.cpp." The up-to-date Velodyne ROS driver should output this information directly. Again, if you are using other lidar sensors, you may need to rename this information. Note that only mechanical lidars are supported by the package currently. - -## Prepare IMU data - - - **IMU requirement**. Like the original LOAM implementation, LIO-SAM only works with a 9-axis IMU, which gives roll, pitch, and yaw estimation. The roll and pitch estimation is mainly used to initialize the system at the correct attitude. The yaw estimation initializes the system at the right heading when using GPS data. Theoretically, an initialization procedure like VINS-Mono will enable LIO-SAM to work with a 6-axis IMU. The performance of the system largely depends on the quality of the IMU measurements. The higher the IMU data rate, the better the system accuracy. We use Microstrain 3DM-GX5-25, which outputs data at 500Hz. We recommend using an IMU that gives at least a 200Hz output rate. Note that the internal IMU of Ouster lidar is an 6-axis IMU. - - - **IMU alignment**. LIO-SAM transforms IMU raw data from the IMU frame to the Lidar frame, which follows the ROS REP-105 convention (x - forward, y - left, z - upward). To make the system function properly, the correct extrinsic transformation needs to be provided in "params.yaml" file. **The reason why there are two extrinsics is that my IMU (Microstrain 3DM-GX5-25) acceleration and attitude have different cooridinates. Depend on your IMU manufacturer, the two extrinsics for your IMU may or may not be the same**. Using our setup as an example: - - we need to set the readings of x-z acceleration and gyro negative to transform the IMU data in the lidar frame, which is indicated by "extrinsicRot" in "params.yaml." - - The transformation of attitude readings is slightly different. We rotate the attitude measurements by -90 degrees around "lidar-z" axis and get the corresponding roll, pitch, and yaw readings in the lidar frame. This transformation is indicated by "extrinsicRPY" in "params.yaml." - - - **IMU debug**. It's strongly recommended that the user uncomment the debug lines in "imuHandler()" of "imageProjection.cpp" and test the output of the transformed IMU data. The user can rotate the sensor suite to check whether the readings correspond to the sensor's movement. A YouTube video that shows the corrected IMU data can be found [here (link to YouTube)](https://youtu.be/BOUK8LYQhHs). - - -

        - drawing -

        -

        - drawing -

        - -## Sample datasets - -For data protection reasons, no data set can currently be made available for ROS2. - -README.md of the master branch contains some links to ROS1 rosbags. Using [ros1_bridge](https://github.com/ros2/ros1_bridge) with these rosbags and this ROS2 branch of LIO-SAM did however not succeeed for timing reasons. - -## Run the package - -1. Run the launch file: -``` -ros2 launch lio_sam run.launch.py -``` - -2. Play existing bag files: -``` -ros2 bag play your-bag.bag -``` - -## Other notes - - - **Loop closure:** The loop function here gives an example of proof of concept. It is directly adapted from LeGO-LOAM loop closure. For more advanced loop closure implementation, please refer to [ScanContext](https://github.com/irapkaist/SC-LeGO-LOAM). Set the "loopClosureEnableFlag" in "params.yaml" to "true" to test the loop closure function. In Rviz, uncheck "Map (cloud)" and check "Map (global)". This is because the visualized map - "Map (cloud)" - is simply a stack of point clouds in Rviz. Their postion will not be updated after pose correction. The loop closure function here is simply adapted from LeGO-LOAM, which is an ICP-based method. Because ICP runs pretty slow, it is suggested that the playback speed is set to be "-r 1". You can try the Garden dataset for testing. - -

        - drawing - drawing -

        - - - **Using GPS:** The park dataset is provided for testing LIO-SAM with GPS data. This dataset is gathered by [Yewei Huang](https://robustfieldautonomylab.github.io/people.html). To enable the GPS function, change "gpsTopic" in "params.yaml" to "odometry/gps". In Rviz, uncheck "Map (cloud)" and check "Map (global)". Also check "Odom GPS", which visualizes the GPS odometry. "gpsCovThreshold" can be adjusted to filter bad GPS readings. "poseCovThreshold" can be used to adjust the frequency of adding GPS factor to the graph. For example, you will notice the trajectory is constantly corrected by GPS whey you set "poseCovThreshold" to 1.0. Because of the heavy iSAM optimization, it's recommended that the playback speed is "-r 1". - -

        - drawing -

        - - - **KITTI:** Since LIO-SAM needs a high-frequency IMU for function properly, we need to use KITTI raw data for testing. One problem remains unsolved is that the intrinsics of the IMU are unknown, which has a big impact on the accuracy of LIO-SAM. Download the provided sample data and make the following changes in "params.yaml": - - extrinsicTrans: [-8.086759e-01, 3.195559e-01, -7.997231e-01] - - extrinsicRot: [9.999976e-01, 7.553071e-04, -2.035826e-03, -7.854027e-04, 9.998898e-01, -1.482298e-02, 2.024406e-03, 1.482454e-02, 9.998881e-01] - - extrinsicRPY: [9.999976e-01, 7.553071e-04, -2.035826e-03, -7.854027e-04, 9.998898e-01, -1.482298e-02, 2.024406e-03, 1.482454e-02, 9.998881e-01] - - N_SCAN: 64 - - downsampleRate: 2 or 4 - - loopClosureEnableFlag: true or false - -

        - drawing - drawing -

        - - - **Ouster lidar:** To make LIO-SAM work with Ouster lidar, some preparations needs to be done on hardware and software level. - - Hardware: - - Use an external IMU. LIO-SAM does not work with the internal 6-axis IMU of Ouster lidar. You need to attach a 9-axis IMU to the lidar and perform data-gathering. - - Configure the driver. Change "timestamp_mode" in your Ouster launch file to "TIME_FROM_PTP_1588" so you can have ROS format timestamp for the point clouds. - - Config: - - Change "sensor" in "params.yaml" to "ouster". - - Change "N_SCAN" and "Horizon_SCAN" in "params.yaml" according to your lidar, i.e., N_SCAN=128, Horizon_SCAN=1024. - - Gen 1 and Gen 2 Ouster: - It seems that the point coordinate definition might be different in different generations. Please refer to [Issue #94](https://github.com/TixiaoShan/LIO-SAM/issues/94) for debugging. - -

        - drawing - drawing -

        - -## Issues - - - **Zigzag or jerking behavior**: if your lidar and IMU data formats are consistent with the requirement of LIO-SAM, this problem is likely caused by un-synced timestamp of lidar and IMU data. - - - **Jumpping up and down**: if you start testing your bag file and the base_link starts to jump up and down immediately, it is likely your IMU extrinsics are wrong. For example, the gravity acceleration has negative value. - - - **mapOptimization crash**: it is usually caused by GTSAM. Please install the GTSAM specified in the README.md. More similar issues can be found [here](https://github.com/TixiaoShan/LIO-SAM/issues). - - - **gps odometry unavailable**: it is generally caused due to unavailable transform between message frame_ids and robot frame_id (for example: transform should be available from "imu_frame_id" and "gps_frame_id" to "base_link" frame. Please read the Robot Localization documentation found [here](http://docs.ros.org/en/melodic/api/robot_localization/html/preparing_sensor_data.html). - -## Paper - -Thank you for citing [LIO-SAM (IROS-2020)](./config/doc/paper.pdf) if you use any of this code. -``` -@inproceedings{liosam2020shan, - title={LIO-SAM: Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping}, - author={Shan, Tixiao and Englot, Brendan and Meyers, Drew and Wang, Wei and Ratti, Carlo and Rus Daniela}, - booktitle={IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)}, - pages={5135-5142}, - year={2020}, - organization={IEEE} -} -``` - -Part of the code is adapted from [LeGO-LOAM](https://github.com/RobustFieldAutonomyLab/LeGO-LOAM). -``` -@inproceedings{legoloam2018shan, - title={LeGO-LOAM: Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain}, - author={Shan, Tixiao and Englot, Brendan}, - booktitle={IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS)}, - pages={4758-4765}, - year={2018}, - organization={IEEE} -} -``` - -## TODO - - - [ ] [Bug within imuPreintegration](https://github.com/TixiaoShan/LIO-SAM/issues/104) - -## Related Package - - - [Lidar-IMU calibration](https://github.com/chennuo0125-HIT/lidar_imu_calib) - - [LIO-SAM with Scan Context](https://github.com/gisbi-kim/SC-LIO-SAM) - -## Acknowledgement - - - LIO-SAM is based on LOAM (J. Zhang and S. Singh. LOAM: Lidar Odometry and Mapping in Real-time). diff --git a/src/mapping/lio_sam/config/doc/demo.gif b/src/mapping/lio_sam/config/doc/demo.gif deleted file mode 100755 index 0517655c6..000000000 Binary files a/src/mapping/lio_sam/config/doc/demo.gif and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/device-boat.png b/src/mapping/lio_sam/config/doc/device-boat.png deleted file mode 100755 index 68f95cf31..000000000 Binary files a/src/mapping/lio_sam/config/doc/device-boat.png and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/device-hand-2.png b/src/mapping/lio_sam/config/doc/device-hand-2.png deleted file mode 100755 index 260d38d32..000000000 Binary files a/src/mapping/lio_sam/config/doc/device-hand-2.png and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/device-hand.png b/src/mapping/lio_sam/config/doc/device-hand.png deleted file mode 100755 index 6b8ad5739..000000000 Binary files a/src/mapping/lio_sam/config/doc/device-hand.png and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/device-jackal.png b/src/mapping/lio_sam/config/doc/device-jackal.png deleted file mode 100755 index 10b371cad..000000000 Binary files a/src/mapping/lio_sam/config/doc/device-jackal.png and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/gps-demo.gif b/src/mapping/lio_sam/config/doc/gps-demo.gif deleted file mode 100755 index 6d182c485..000000000 Binary files a/src/mapping/lio_sam/config/doc/gps-demo.gif and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/imu-debug.gif b/src/mapping/lio_sam/config/doc/imu-debug.gif deleted file mode 100755 index 8ec979fdd..000000000 Binary files a/src/mapping/lio_sam/config/doc/imu-debug.gif and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/imu-transform.png b/src/mapping/lio_sam/config/doc/imu-transform.png deleted file mode 100755 index a11bc159d..000000000 Binary files a/src/mapping/lio_sam/config/doc/imu-transform.png and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/kitti-demo.gif b/src/mapping/lio_sam/config/doc/kitti-demo.gif deleted file mode 100755 index 499bbd594..000000000 Binary files a/src/mapping/lio_sam/config/doc/kitti-demo.gif and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/kitti-map.png b/src/mapping/lio_sam/config/doc/kitti-map.png deleted file mode 100755 index d134d1dba..000000000 Binary files a/src/mapping/lio_sam/config/doc/kitti-map.png and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/kitti2bag/README.md b/src/mapping/lio_sam/config/doc/kitti2bag/README.md deleted file mode 100755 index 2cfbd0989..000000000 --- a/src/mapping/lio_sam/config/doc/kitti2bag/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# kitti2bag - -## How to run it? - -```bash -wget https://s3.eu-central-1.amazonaws.com/avg-kitti/raw_data/2011_09_26_drive_0084/2011_09_26_drive_0084_sync.zip -wget https://s3.eu-central-1.amazonaws.com/avg-kitti/raw_data/2011_09_26_drive_0084/2011_09_26_drive_0084_extract.zip -wget https://s3.eu-central-1.amazonaws.com/avg-kitti/raw_data/2011_09_26_calib.zip -unzip 2011_09_26_drive_0084_sync.zip -unzip 2011_09_26_drive_0084_extract.zip -unzip 2011_09_26_calib.zip -python kitti2bag.py -t 2011_09_26 -r 0084 raw_synced . -``` - -That's it. You have a bag that contains your data. - -Other source files can be found at [KITTI raw data](http://www.cvlibs.net/datasets/kitti/raw_data.php) page. \ No newline at end of file diff --git a/src/mapping/lio_sam/config/doc/kitti2bag/kitti2bag.py b/src/mapping/lio_sam/config/doc/kitti2bag/kitti2bag.py deleted file mode 100755 index 03f3dcb4d..000000000 --- a/src/mapping/lio_sam/config/doc/kitti2bag/kitti2bag.py +++ /dev/null @@ -1,473 +0,0 @@ -#!env python -# -*- coding: utf-8 -*- - -import sys - -try: - import pykitti -except ImportError as e: - print('Could not load module \'pykitti\'. Please run `pip install pykitti`') - sys.exit(1) - -import tf -import os -import cv2 -import rospy -import rosbag -from tqdm import tqdm -from tf2_msgs.msg import TFMessage -from datetime import datetime -from std_msgs.msg import Header -from sensor_msgs.msg import CameraInfo, Imu, PointField, NavSatFix -import sensor_msgs.point_cloud2 as pcl2 -from geometry_msgs.msg import TransformStamped, TwistStamped, Transform -from cv_bridge import CvBridge -import numpy as np -import argparse - -def save_imu_data(bag, kitti, imu_frame_id, topic): - print("Exporting IMU") - for timestamp, oxts in zip(kitti.timestamps, kitti.oxts): - q = tf.transformations.quaternion_from_euler(oxts.packet.roll, oxts.packet.pitch, oxts.packet.yaw) - imu = Imu() - imu.header.frame_id = imu_frame_id - imu.header.stamp = rospy.Time.from_sec(float(timestamp.strftime("%s.%f"))) - imu.orientation.x = q[0] - imu.orientation.y = q[1] - imu.orientation.z = q[2] - imu.orientation.w = q[3] - imu.linear_acceleration.x = oxts.packet.af - imu.linear_acceleration.y = oxts.packet.al - imu.linear_acceleration.z = oxts.packet.au - imu.angular_velocity.x = oxts.packet.wf - imu.angular_velocity.y = oxts.packet.wl - imu.angular_velocity.z = oxts.packet.wu - bag.write(topic, imu, t=imu.header.stamp) - -def save_imu_data_raw(bag, kitti, imu_frame_id, topic): - print("Exporting IMU Raw") - synced_path = kitti.data_path - unsynced_path = synced_path.replace('sync', 'extract') - imu_path = os.path.join(unsynced_path, 'oxts') - - # read time stamp (convert to ros seconds format) - with open(os.path.join(imu_path, 'timestamps.txt')) as f: - lines = f.readlines() - imu_datetimes = [] - for line in lines: - if len(line) == 1: - continue - timestamp = datetime.strptime(line[:-4], '%Y-%m-%d %H:%M:%S.%f') - imu_datetimes.append(float(timestamp.strftime("%s.%f"))) - - # fix imu time using a linear model (may not be ideal, ^_^) - imu_index = np.asarray(range(len(imu_datetimes)), dtype=np.float64) - z = np.polyfit(imu_index, imu_datetimes, 1) - imu_datetimes_new = z[0] * imu_index + z[1] - imu_datetimes = imu_datetimes_new.tolist() - - # get all imu data - imu_data_dir = os.path.join(imu_path, 'data') - imu_filenames = sorted(os.listdir(imu_data_dir)) - imu_data = [None] * len(imu_filenames) - for i, imu_file in enumerate(imu_filenames): - imu_data_file = open(os.path.join(imu_data_dir, imu_file), "r") - for line in imu_data_file: - if len(line) == 1: - continue - stripped_line = line.strip() - line_list = stripped_line.split() - imu_data[i] = line_list - - assert len(imu_datetimes) == len(imu_data) - - for timestamp, data in zip(imu_datetimes, imu_data): - roll, pitch, yaw = float(data[3]), float(data[4]), float(data[5]), - q = tf.transformations.quaternion_from_euler(roll, pitch, yaw) - imu = Imu() - imu.header.frame_id = imu_frame_id - imu.header.stamp = rospy.Time.from_sec(timestamp) - imu.orientation.x = q[0] - imu.orientation.y = q[1] - imu.orientation.z = q[2] - imu.orientation.w = q[3] - imu.linear_acceleration.x = float(data[11]) - imu.linear_acceleration.y = float(data[12]) - imu.linear_acceleration.z = float(data[13]) - imu.angular_velocity.x = float(data[17]) - imu.angular_velocity.y = float(data[18]) - imu.angular_velocity.z = float(data[19]) - bag.write(topic, imu, t=imu.header.stamp) - - imu.header.frame_id = 'imu_enu_link' - bag.write('/imu_correct', imu, t=imu.header.stamp) # for LIO-SAM GPS - -def save_dynamic_tf(bag, kitti, kitti_type, initial_time): - print("Exporting time dependent transformations") - if kitti_type.find("raw") != -1: - for timestamp, oxts in zip(kitti.timestamps, kitti.oxts): - tf_oxts_msg = TFMessage() - tf_oxts_transform = TransformStamped() - tf_oxts_transform.header.stamp = rospy.Time.from_sec(float(timestamp.strftime("%s.%f"))) - tf_oxts_transform.header.frame_id = 'world' - tf_oxts_transform.child_frame_id = 'base_link' - - transform = (oxts.T_w_imu) - t = transform[0:3, 3] - q = tf.transformations.quaternion_from_matrix(transform) - oxts_tf = Transform() - - oxts_tf.translation.x = t[0] - oxts_tf.translation.y = t[1] - oxts_tf.translation.z = t[2] - - oxts_tf.rotation.x = q[0] - oxts_tf.rotation.y = q[1] - oxts_tf.rotation.z = q[2] - oxts_tf.rotation.w = q[3] - - tf_oxts_transform.transform = oxts_tf - tf_oxts_msg.transforms.append(tf_oxts_transform) - - bag.write('/tf', tf_oxts_msg, tf_oxts_msg.transforms[0].header.stamp) - - elif kitti_type.find("odom") != -1: - timestamps = map(lambda x: initial_time + x.total_seconds(), kitti.timestamps) - for timestamp, tf_matrix in zip(timestamps, kitti.T_w_cam0): - tf_msg = TFMessage() - tf_stamped = TransformStamped() - tf_stamped.header.stamp = rospy.Time.from_sec(timestamp) - tf_stamped.header.frame_id = 'world' - tf_stamped.child_frame_id = 'camera_left' - - t = tf_matrix[0:3, 3] - q = tf.transformations.quaternion_from_matrix(tf_matrix) - transform = Transform() - - transform.translation.x = t[0] - transform.translation.y = t[1] - transform.translation.z = t[2] - - transform.rotation.x = q[0] - transform.rotation.y = q[1] - transform.rotation.z = q[2] - transform.rotation.w = q[3] - - tf_stamped.transform = transform - tf_msg.transforms.append(tf_stamped) - - bag.write('/tf', tf_msg, tf_msg.transforms[0].header.stamp) - -def save_camera_data(bag, kitti_type, kitti, util, bridge, camera, camera_frame_id, topic, initial_time): - print("Exporting camera {}".format(camera)) - if kitti_type.find("raw") != -1: - camera_pad = '{0:02d}'.format(camera) - image_dir = os.path.join(kitti.data_path, 'image_{}'.format(camera_pad)) - image_path = os.path.join(image_dir, 'data') - image_filenames = sorted(os.listdir(image_path)) - with open(os.path.join(image_dir, 'timestamps.txt')) as f: - image_datetimes = map(lambda x: datetime.strptime(x[:-4], '%Y-%m-%d %H:%M:%S.%f'), f.readlines()) - - calib = CameraInfo() - calib.header.frame_id = camera_frame_id - calib.width, calib.height = tuple(util['S_rect_{}'.format(camera_pad)].tolist()) - calib.distortion_model = 'plumb_bob' - calib.K = util['K_{}'.format(camera_pad)] - calib.R = util['R_rect_{}'.format(camera_pad)] - calib.D = util['D_{}'.format(camera_pad)] - calib.P = util['P_rect_{}'.format(camera_pad)] - - elif kitti_type.find("odom") != -1: - camera_pad = '{0:01d}'.format(camera) - image_path = os.path.join(kitti.sequence_path, 'image_{}'.format(camera_pad)) - image_filenames = sorted(os.listdir(image_path)) - image_datetimes = map(lambda x: initial_time + x.total_seconds(), kitti.timestamps) - - calib = CameraInfo() - calib.header.frame_id = camera_frame_id - calib.P = util['P{}'.format(camera_pad)] - - iterable = zip(image_datetimes, image_filenames) - for dt, filename in tqdm(iterable, total=len(image_filenames)): - image_filename = os.path.join(image_path, filename) - cv_image = cv2.imread(image_filename) - calib.height, calib.width = cv_image.shape[:2] - if camera in (0, 1): - cv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY) - encoding = "mono8" if camera in (0, 1) else "bgr8" - image_message = bridge.cv2_to_imgmsg(cv_image, encoding=encoding) - image_message.header.frame_id = camera_frame_id - if kitti_type.find("raw") != -1: - image_message.header.stamp = rospy.Time.from_sec(float(datetime.strftime(dt, "%s.%f"))) - topic_ext = "/image_raw" - elif kitti_type.find("odom") != -1: - image_message.header.stamp = rospy.Time.from_sec(dt) - topic_ext = "/image_rect" - calib.header.stamp = image_message.header.stamp - bag.write(topic + topic_ext, image_message, t = image_message.header.stamp) - bag.write(topic + '/camera_info', calib, t = calib.header.stamp) - -def save_velo_data(bag, kitti, velo_frame_id, topic): - print("Exporting velodyne data") - velo_path = os.path.join(kitti.data_path, 'velodyne_points') - velo_data_dir = os.path.join(velo_path, 'data') - velo_filenames = sorted(os.listdir(velo_data_dir)) - with open(os.path.join(velo_path, 'timestamps.txt')) as f: - lines = f.readlines() - velo_datetimes = [] - for line in lines: - if len(line) == 1: - continue - dt = datetime.strptime(line[:-4], '%Y-%m-%d %H:%M:%S.%f') - velo_datetimes.append(dt) - - iterable = zip(velo_datetimes, velo_filenames) - - count = 0 - - for dt, filename in tqdm(iterable, total=len(velo_filenames)): - if dt is None: - continue - - velo_filename = os.path.join(velo_data_dir, filename) - - # read binary data - scan = (np.fromfile(velo_filename, dtype=np.float32)).reshape(-1, 4) - - # get ring channel - depth = np.linalg.norm(scan, 2, axis=1) - pitch = np.arcsin(scan[:, 2] / depth) # arcsin(z, depth) - fov_down = -24.8 / 180.0 * np.pi - fov = (abs(-24.8) + abs(2.0)) / 180.0 * np.pi - proj_y = (pitch + abs(fov_down)) / fov # in [0.0, 1.0] - proj_y *= 64 # in [0.0, H] - proj_y = np.floor(proj_y) - proj_y = np.minimum(64 - 1, proj_y) - proj_y = np.maximum(0, proj_y).astype(np.int32) # in [0,H-1] - proj_y = proj_y.reshape(-1, 1) - scan = np.concatenate((scan,proj_y), axis=1) - scan = scan.tolist() - for i in range(len(scan)): - scan[i][-1] = int(scan[i][-1]) - - # create header - header = Header() - header.frame_id = velo_frame_id - header.stamp = rospy.Time.from_sec(float(datetime.strftime(dt, "%s.%f"))) - - # fill pcl msg - fields = [PointField('x', 0, PointField.FLOAT32, 1), - PointField('y', 4, PointField.FLOAT32, 1), - PointField('z', 8, PointField.FLOAT32, 1), - PointField('intensity', 12, PointField.FLOAT32, 1), - PointField('ring', 16, PointField.UINT16, 1)] - pcl_msg = pcl2.create_cloud(header, fields, scan) - pcl_msg.is_dense = True - # print(pcl_msg) - - bag.write(topic, pcl_msg, t=pcl_msg.header.stamp) - - # count += 1 - # if count > 200: - # break - -def get_static_transform(from_frame_id, to_frame_id, transform): - t = transform[0:3, 3] - q = tf.transformations.quaternion_from_matrix(transform) - tf_msg = TransformStamped() - tf_msg.header.frame_id = from_frame_id - tf_msg.child_frame_id = to_frame_id - tf_msg.transform.translation.x = float(t[0]) - tf_msg.transform.translation.y = float(t[1]) - tf_msg.transform.translation.z = float(t[2]) - tf_msg.transform.rotation.x = float(q[0]) - tf_msg.transform.rotation.y = float(q[1]) - tf_msg.transform.rotation.z = float(q[2]) - tf_msg.transform.rotation.w = float(q[3]) - return tf_msg - - -def inv(transform): - "Invert rigid body transformation matrix" - R = transform[0:3, 0:3] - t = transform[0:3, 3] - t_inv = -1 * R.T.dot(t) - transform_inv = np.eye(4) - transform_inv[0:3, 0:3] = R.T - transform_inv[0:3, 3] = t_inv - return transform_inv - - -def save_static_transforms(bag, transforms, timestamps): - print("Exporting static transformations") - tfm = TFMessage() - for transform in transforms: - t = get_static_transform(from_frame_id=transform[0], to_frame_id=transform[1], transform=transform[2]) - tfm.transforms.append(t) - for timestamp in timestamps: - time = rospy.Time.from_sec(float(timestamp.strftime("%s.%f"))) - for i in range(len(tfm.transforms)): - tfm.transforms[i].header.stamp = time - bag.write('/tf_static', tfm, t=time) - - -def save_gps_fix_data(bag, kitti, gps_frame_id, topic): - for timestamp, oxts in zip(kitti.timestamps, kitti.oxts): - navsatfix_msg = NavSatFix() - navsatfix_msg.header.frame_id = gps_frame_id - navsatfix_msg.header.stamp = rospy.Time.from_sec(float(timestamp.strftime("%s.%f"))) - navsatfix_msg.latitude = oxts.packet.lat - navsatfix_msg.longitude = oxts.packet.lon - navsatfix_msg.altitude = oxts.packet.alt - navsatfix_msg.status.service = 1 - bag.write(topic, navsatfix_msg, t=navsatfix_msg.header.stamp) - - -def save_gps_vel_data(bag, kitti, gps_frame_id, topic): - for timestamp, oxts in zip(kitti.timestamps, kitti.oxts): - twist_msg = TwistStamped() - twist_msg.header.frame_id = gps_frame_id - twist_msg.header.stamp = rospy.Time.from_sec(float(timestamp.strftime("%s.%f"))) - twist_msg.twist.linear.x = oxts.packet.vf - twist_msg.twist.linear.y = oxts.packet.vl - twist_msg.twist.linear.z = oxts.packet.vu - twist_msg.twist.angular.x = oxts.packet.wf - twist_msg.twist.angular.y = oxts.packet.wl - twist_msg.twist.angular.z = oxts.packet.wu - bag.write(topic, twist_msg, t=twist_msg.header.stamp) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description = "Convert KITTI dataset to ROS bag file the easy way!") - # Accepted argument values - kitti_types = ["raw_synced", "odom_color", "odom_gray"] - odometry_sequences = [] - for s in range(22): - odometry_sequences.append(str(s).zfill(2)) - - parser.add_argument("kitti_type", choices = kitti_types, help = "KITTI dataset type") - parser.add_argument("dir", nargs = "?", default = os.getcwd(), help = "base directory of the dataset, if no directory passed the deafult is current working directory") - parser.add_argument("-t", "--date", help = "date of the raw dataset (i.e. 2011_09_26), option is only for RAW datasets.") - parser.add_argument("-r", "--drive", help = "drive number of the raw dataset (i.e. 0001), option is only for RAW datasets.") - parser.add_argument("-s", "--sequence", choices = odometry_sequences,help = "sequence of the odometry dataset (between 00 - 21), option is only for ODOMETRY datasets.") - args = parser.parse_args() - - bridge = CvBridge() - compression = rosbag.Compression.NONE - # compression = rosbag.Compression.BZ2 - # compression = rosbag.Compression.LZ4 - - # CAMERAS - cameras = [ - (0, 'camera_gray_left', '/kitti/camera_gray_left'), - (1, 'camera_gray_right', '/kitti/camera_gray_right'), - (2, 'camera_color_left', '/kitti/camera_color_left'), - (3, 'camera_color_right', '/kitti/camera_color_right') - ] - - if args.kitti_type.find("raw") != -1: - - if args.date == None: - print("Date option is not given. It is mandatory for raw dataset.") - print("Usage for raw dataset: kitti2bag raw_synced [dir] -t -r ") - sys.exit(1) - elif args.drive == None: - print("Drive option is not given. It is mandatory for raw dataset.") - print("Usage for raw dataset: kitti2bag raw_synced [dir] -t -r ") - sys.exit(1) - - bag = rosbag.Bag("kitti_{}_drive_{}_{}.bag".format(args.date, args.drive, args.kitti_type[4:]), 'w', compression=compression) - kitti = pykitti.raw(args.dir, args.date, args.drive) - if not os.path.exists(kitti.data_path): - print('Path {} does not exists. Exiting.'.format(kitti.data_path)) - sys.exit(1) - - if len(kitti.timestamps) == 0: - print('Dataset is empty? Exiting.') - sys.exit(1) - - try: - # IMU - imu_frame_id = 'imu_link' - imu_topic = '/kitti/oxts/imu' - imu_raw_topic = '/imu_raw' - gps_fix_topic = '/gps/fix' - gps_vel_topic = '/gps/vel' - velo_frame_id = 'velodyne' - velo_topic = '/points_raw' - - T_base_link_to_imu = np.eye(4, 4) - T_base_link_to_imu[0:3, 3] = [-2.71/2.0-0.05, 0.32, 0.93] - - # tf_static - transforms = [ - ('base_link', imu_frame_id, T_base_link_to_imu), - (imu_frame_id, velo_frame_id, inv(kitti.calib.T_velo_imu)), - (imu_frame_id, cameras[0][1], inv(kitti.calib.T_cam0_imu)), - (imu_frame_id, cameras[1][1], inv(kitti.calib.T_cam1_imu)), - (imu_frame_id, cameras[2][1], inv(kitti.calib.T_cam2_imu)), - (imu_frame_id, cameras[3][1], inv(kitti.calib.T_cam3_imu)) - ] - - util = pykitti.utils.read_calib_file(os.path.join(kitti.calib_path, 'calib_cam_to_cam.txt')) - - # Export - # save_static_transforms(bag, transforms, kitti.timestamps) - # save_dynamic_tf(bag, kitti, args.kitti_type, initial_time=None) - # save_imu_data(bag, kitti, imu_frame_id, imu_topic) - save_imu_data_raw(bag, kitti, imu_frame_id, imu_raw_topic) - save_gps_fix_data(bag, kitti, imu_frame_id, gps_fix_topic) - save_gps_vel_data(bag, kitti, imu_frame_id, gps_vel_topic) - for camera in cameras: - save_camera_data(bag, args.kitti_type, kitti, util, bridge, camera=camera[0], camera_frame_id=camera[1], topic=camera[2], initial_time=None) - break - save_velo_data(bag, kitti, velo_frame_id, velo_topic) - - finally: - print("## OVERVIEW ##") - print(bag) - bag.close() - - elif args.kitti_type.find("odom") != -1: - - if args.sequence == None: - print("Sequence option is not given. It is mandatory for odometry dataset.") - print("Usage for odometry dataset: kitti2bag {odom_color, odom_gray} [dir] -s ") - sys.exit(1) - - bag = rosbag.Bag("kitti_data_odometry_{}_sequence_{}.bag".format(args.kitti_type[5:],args.sequence), 'w', compression=compression) - - kitti = pykitti.odometry(args.dir, args.sequence) - if not os.path.exists(kitti.sequence_path): - print('Path {} does not exists. Exiting.'.format(kitti.sequence_path)) - sys.exit(1) - - kitti.load_calib() - kitti.load_timestamps() - - if len(kitti.timestamps) == 0: - print('Dataset is empty? Exiting.') - sys.exit(1) - - if args.sequence in odometry_sequences[:11]: - print("Odometry dataset sequence {} has ground truth information (poses).".format(args.sequence)) - kitti.load_poses() - - try: - util = pykitti.utils.read_calib_file(os.path.join(args.dir,'sequences',args.sequence, 'calib.txt')) - current_epoch = (datetime.utcnow() - datetime(1970, 1, 1)).total_seconds() - # Export - if args.kitti_type.find("gray") != -1: - used_cameras = cameras[:2] - elif args.kitti_type.find("color") != -1: - used_cameras = cameras[-2:] - - save_dynamic_tf(bag, kitti, args.kitti_type, initial_time=current_epoch) - for camera in used_cameras: - save_camera_data(bag, args.kitti_type, kitti, util, bridge, camera=camera[0], camera_frame_id=camera[1], topic=camera[2], initial_time=current_epoch) - - finally: - print("## OVERVIEW ##") - print(bag) - bag.close() - diff --git a/src/mapping/lio_sam/config/doc/loop-closure-2.gif b/src/mapping/lio_sam/config/doc/loop-closure-2.gif deleted file mode 100755 index f46ac1fa5..000000000 Binary files a/src/mapping/lio_sam/config/doc/loop-closure-2.gif and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/loop-closure.gif b/src/mapping/lio_sam/config/doc/loop-closure.gif deleted file mode 100755 index 8413455c4..000000000 Binary files a/src/mapping/lio_sam/config/doc/loop-closure.gif and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/ouster-demo.gif b/src/mapping/lio_sam/config/doc/ouster-demo.gif deleted file mode 100755 index 0ae266d43..000000000 Binary files a/src/mapping/lio_sam/config/doc/ouster-demo.gif and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/ouster-device.jpg b/src/mapping/lio_sam/config/doc/ouster-device.jpg deleted file mode 100755 index 627e8eda6..000000000 Binary files a/src/mapping/lio_sam/config/doc/ouster-device.jpg and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/paper.pdf b/src/mapping/lio_sam/config/doc/paper.pdf deleted file mode 100755 index 394365aca..000000000 Binary files a/src/mapping/lio_sam/config/doc/paper.pdf and /dev/null differ diff --git a/src/mapping/lio_sam/config/doc/system.png b/src/mapping/lio_sam/config/doc/system.png deleted file mode 100755 index 43d1d9978..000000000 Binary files a/src/mapping/lio_sam/config/doc/system.png and /dev/null differ diff --git a/src/mapping/lio_sam/config/params.yaml b/src/mapping/lio_sam/config/params.yaml index 94b676608..2ed9dee3f 100755 --- a/src/mapping/lio_sam/config/params.yaml +++ b/src/mapping/lio_sam/config/params.yaml @@ -2,13 +2,13 @@ ros__parameters: # Topics - pointCloudTopic: "/lidar_front/points_raw" # Point cloud data + pointCloudTopic: "/lidar_right/points_raw" # Point cloud data imuTopic: "/fakeimu" # IMU data odomTopic: "odometry/imu" # IMU pre-preintegration odometry, same frequency as IMU gpsTopic: "/gps/odom" # GPS odometry topic from navsat, see module_navsat.launch file # Frames - lidarFrame: "lidar_front" + lidarFrame: "lidar_right" baselinkFrame: "base_link" odometryFrame: "odom" mapFrame: "map" diff --git a/src/mapping/lio_sam/config/robot.urdf.xacro b/src/mapping/lio_sam/config/robot.urdf.xacro deleted file mode 100755 index 604363e30..000000000 --- a/src/mapping/lio_sam/config/robot.urdf.xacro +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/mapping/lio_sam/config/rviz2.rviz b/src/mapping/lio_sam/config/rviz2.rviz deleted file mode 100755 index 7d5816926..000000000 --- a/src/mapping/lio_sam/config/rviz2.rviz +++ /dev/null @@ -1,308 +0,0 @@ -Panels: - - Class: rviz_common/Displays - Help Height: 138 - Name: Displays - Property Tree Widget: - Expanded: - - /Global Options1 - - /Status1 - - /PointCloud21 - - /TF1 - - /MarkerArray1 - - /PointCloud22 - - /PointCloud22/Topic1 - - /PointCloud23 - Splitter Ratio: 0.5519230961799622 - Tree Height: 1628 - - Class: rviz_common/Selection - Name: Selection - - Class: rviz_common/Tool Properties - Expanded: - - /2D Goal Pose1 - - /Publish Point1 - Name: Tool Properties - Splitter Ratio: 0.5886790156364441 - - Class: rviz_common/Views - Expanded: - - /Current View1 - Name: Views - Splitter Ratio: 0.5 -Visualization Manager: - Class: "" - Displays: - - Alpha: 0.5 - Cell Size: 1 - Class: rviz_default_plugins/Grid - Color: 160; 160; 164 - Enabled: true - Line Style: - Line Width: 0.029999999329447746 - Value: Lines - Name: Grid - Normal Cell Count: 0 - Offset: - X: 0 - Y: 0 - Z: 0 - Plane: XY - Plane Cell Count: 10 - Reference Frame: - Value: true - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 15.179542541503906 - Min Value: -3.752213716506958 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: AxisColor - Decay Time: 1000 - Enabled: false - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 92.95751190185547 - Min Color: 0; 0; 0 - Min Intensity: 5.530245304107666 - Name: PointCloud2 - Position Transformer: XYZ - Selectable: true - Size (Pixels): 1 - Size (m): 0.009999999776482582 - Style: Points - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /lio_sam/mapping/cloud_registered - Use Fixed Frame: true - Use rainbow: true - Value: false - - Class: rviz_default_plugins/TF - Enabled: true - Frame Timeout: 15 - Frames: - All Enabled: true - base_link: - Value: true - chassis_link: - Value: true - imu_link: - Value: true - laser_sensor_frame: - Value: true - lidar_link: - Value: true - map: - Value: true - navsat_link: - Value: true - odom: - Value: true - Marker Scale: 100 - Name: TF - Show Arrows: true - Show Axes: true - Show Names: false - Tree: - map: - odom: - base_link: - chassis_link: - imu_link: - laser_sensor_frame: - {} - navsat_link: - {} - lidar_link: - {} - Update Interval: 0 - Value: true - - Alpha: 1 - Buffer Length: 1 - Class: rviz_default_plugins/Path - Color: 85; 255; 255 - Enabled: true - Head Diameter: 0.30000001192092896 - Head Length: 0.20000000298023224 - Length: 0.30000001192092896 - Line Style: Billboards - Line Width: 0.029999999329447746 - Name: Path - Offset: - X: 0 - Y: 0 - Z: 0 - Pose Color: 255; 85; 255 - Pose Style: None - Radius: 0.029999999329447746 - Shaft Diameter: 0.10000000149011612 - Shaft Length: 0.10000000149011612 - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /lio_sam/mapping/path - Value: true - - Class: rviz_default_plugins/MarkerArray - Enabled: true - Name: MarkerArray - Namespaces: - loop_edges: true - loop_nodes: true - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /lio_sam/mapping/loop_closure_constraints - Value: true - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: "" - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 4096 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: PointCloud2 - Position Transformer: "" - Selectable: true - Size (Pixels): 3 - Size (m): 0.009999999776482582 - Style: Flat Squares - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: System Default - Value: /points - Use Fixed Frame: true - Use rainbow: true - Value: true - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 22.32850456237793 - Min Value: -20.848865509033203 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz_default_plugins/PointCloud2 - Color: 255; 255; 255 - Color Transformer: AxisColor - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 0 - Min Color: 0; 0; 0 - Min Intensity: 0 - Name: PointCloud2 - Position Transformer: XYZ - Selectable: true - Size (Pixels): 3 - Size (m): 0.800000011920929 - Style: Spheres - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /lio_sam/mapping/map_global - Use Fixed Frame: true - Use rainbow: true - Value: true - Enabled: true - Global Options: - Background Color: 48; 48; 48 - Fixed Frame: map - Frame Rate: 30 - Name: root - Tools: - - Class: rviz_default_plugins/Interact - Hide Inactive Objects: true - - Class: rviz_default_plugins/MoveCamera - - Class: rviz_default_plugins/Select - - Class: rviz_default_plugins/FocusCamera - - Class: rviz_default_plugins/Measure - Line color: 128; 128; 0 - - Class: rviz_default_plugins/SetInitialPose - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /initialpose - - Class: rviz_default_plugins/SetGoal - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /goal_pose - - Class: rviz_default_plugins/PublishPoint - Single click: true - Topic: - Depth: 5 - Durability Policy: Volatile - History Policy: Keep Last - Reliability Policy: Reliable - Value: /clicked_point - Transformation: - Current: - Class: rviz_default_plugins/TF - Value: true - Views: - Current: - Class: rviz_default_plugins/Orbit - Distance: 973.274658203125 - Enable Stereo Rendering: - Stereo Eye Separation: 0.05999999865889549 - Stereo Focal Distance: 1 - Swap Stereo Eyes: false - Value: false - Focal Point: - X: 32.988704681396484 - Y: 48.207252502441406 - Z: -122.1219711303711 - Focal Shape Fixed Size: true - Focal Shape Size: 0.05000000074505806 - Invert Z Axis: false - Name: Current View - Near Clip Distance: 0.009999999776482582 - Pitch: 0.9297972917556763 - Target Frame: - Value: Orbit (rviz) - Yaw: 3.208577871322632 - Saved: ~ -Window Geometry: - Displays: - collapsed: false - Height: 2032 - Hide Left Dock: false - Hide Right Dock: true - QMainWindow State: 000000ff00000000fd0000000400000000000001f700000754fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b000000b000fffffffb0000001e0054006f006f006c002000500072006f00700065007200740069006500730200000774000000a600000185000000b2fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000006e000007540000018200fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000015f00000754fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000006e000007540000013200fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d0065010000000000000450000000000000000000000c6d0000075400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 - Selection: - collapsed: false - Tool Properties: - collapsed: false - Views: - collapsed: true - Width: 3696 - X: 144 - Y: 54 diff --git a/src/mapping/lio_sam/include/lio_sam/utility.hpp b/src/mapping/lio_sam/include/lio_sam/utility.hpp deleted file mode 100755 index 23a5814ab..000000000 --- a/src/mapping/lio_sam/include/lio_sam/utility.hpp +++ /dev/null @@ -1,444 +0,0 @@ -#pragma once -#ifndef _UTILITY_LIDAR_ODOMETRY_H_ -#define _UTILITY_LIDAR_ODOMETRY_H_ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -typedef pcl::PointXYZI PointType; - -enum class SensorType { VELODYNE, OUSTER, RINGLESS_VLP_16 }; - -class ParamServer : public rclcpp::Node -{ -public: - std::string robot_id; - - //Topics - string pointCloudTopic; - string imuTopic; - string odomTopic; - string gpsTopic; - - //Frames - string lidarFrame; - string baselinkFrame; - string odometryFrame; - string mapFrame; - - // GPS Settings - bool useImuHeadingInitialization; - bool useGpsElevation; - float gpsCovThreshold; - float poseCovThreshold; - - // Save pcd - bool savePCD; - string savePCDDirectory; - - // Lidar Sensor Configuration - SensorType sensor = SensorType::RINGLESS_VLP_16; // TODO: Move to param file (WSH) - float fov_deg = 20.0; - float fov_below_middle_deg = 10; // This is the portion of the Lidar scan (fov_deg) below the horizon - int N_SCAN; - int Horizon_SCAN; - int downsampleRate; - float lidarMinRange; - float lidarMaxRange; - - // IMU - float imuAccNoise; - float imuGyrNoise; - float imuAccBiasN; - float imuGyrBiasN; - float imuGravity; - float imuRPYWeight; - vector extRotV; - vector extRPYV; - vector extTransV; - Eigen::Matrix3d extRot; - Eigen::Matrix3d extRPY; - Eigen::Vector3d extTrans; - Eigen::Quaterniond extQRPY; - - // LOAM - float edgeThreshold; - float surfThreshold; - int edgeFeatureMinValidNum; - int surfFeatureMinValidNum; - - // voxel filter paprams - float odometrySurfLeafSize; - float mappingCornerLeafSize; - float mappingSurfLeafSize ; - - float z_tollerance; - float rotation_tollerance; - - // CPU Params - int numberOfCores; - double mappingProcessInterval; - - // Surrounding map - float surroundingkeyframeAddingDistThreshold; - float surroundingkeyframeAddingAngleThreshold; - float surroundingKeyframeDensity; - float surroundingKeyframeSearchRadius; - - // Loop closure - bool loopClosureEnableFlag; - float loopClosureFrequency; - int surroundingKeyframeSize; - float historyKeyframeSearchRadius; - float historyKeyframeSearchTimeDiff; - int historyKeyframeSearchNum; - float historyKeyframeFitnessScore; - - // global map visualization radius - float globalMapVisualizationSearchRadius; - float globalMapVisualizationPoseDensity; - float globalMapVisualizationLeafSize; - - ParamServer(std::string node_name, const rclcpp::NodeOptions & options) : Node(node_name, options) - { - declare_parameter("pointCloudTopic", "points"); - get_parameter("pointCloudTopic", pointCloudTopic); - declare_parameter("imuTopic", "imu/data"); - get_parameter("imuTopic", imuTopic); - declare_parameter("odomTopic", "lio_sam/odometry/imu"); - get_parameter("odomTopic", odomTopic); - declare_parameter("gpsTopic", "lio_sam/odometry/gps"); - get_parameter("gpsTopic", gpsTopic); - - declare_parameter("lidarFrame", "laser_data_frame"); - get_parameter("lidarFrame", lidarFrame); - declare_parameter("baselinkFrame", "base_link"); - get_parameter("baselinkFrame", baselinkFrame); - declare_parameter("odometryFrame", "odom"); - get_parameter("odometryFrame", odometryFrame); - declare_parameter("mapFrame", "map"); - get_parameter("mapFrame", mapFrame); - - declare_parameter("useImuHeadingInitialization", false); - get_parameter("useImuHeadingInitialization", useImuHeadingInitialization); - declare_parameter("useGpsElevation", false); - get_parameter("useGpsElevation", useGpsElevation); - declare_parameter("gpsCovThreshold", 2.0); - get_parameter("gpsCovThreshold", gpsCovThreshold); - declare_parameter("poseCovThreshold", 25.0); - get_parameter("poseCovThreshold", poseCovThreshold); - - declare_parameter("savePCD", false); - get_parameter("savePCD", savePCD); - - declare_parameter("savePCDDirectory", "/Downloads/LOAM/"); - get_parameter("savePCDDirectory", savePCDDirectory); - - declare_parameter("N_SCAN", 64); - get_parameter("N_SCAN", N_SCAN); - declare_parameter("Horizon_SCAN", 512); - get_parameter("Horizon_SCAN", Horizon_SCAN); - declare_parameter("downsampleRate", 1); - get_parameter("downsampleRate", downsampleRate); - declare_parameter("lidarMinRange", 5.5); - get_parameter("lidarMinRange", lidarMinRange); - declare_parameter("lidarMaxRange", 1000.0); - get_parameter("lidarMaxRange", lidarMaxRange); - - declare_parameter("imuAccNoise", 9e-4); - get_parameter("imuAccNoise", imuAccNoise); - declare_parameter("imuGyrNoise", 1.6e-4); - get_parameter("imuGyrNoise", imuGyrNoise); - declare_parameter("imuAccBiasN", 5e-4); - get_parameter("imuAccBiasN", imuAccBiasN); - declare_parameter("imuGyrBiasN", 7e-5); - get_parameter("imuGyrBiasN", imuGyrBiasN); - declare_parameter("imuGravity", 9.80511); - get_parameter("imuGravity", imuGravity); - declare_parameter("imuRPYWeight", 0.01); - get_parameter("imuRPYWeight", imuRPYWeight); - - double ida[] = { 1.0, 0.0, 0.0, - 0.0, 1.0, 0.0, - 0.0, 0.0, 1.0}; - std::vector < double > id(ida, std::end(ida)); - declare_parameter("extrinsicRot", id); - get_parameter("extrinsicRot", extRotV); - declare_parameter("extrinsicRPY", id); - get_parameter("extrinsicRPY", extRPYV); - double zea[] = {0.0, 0.0, 0.0}; - std::vector < double > ze(zea, std::end(zea)); - declare_parameter("extrinsicTrans", ze); - get_parameter("extrinsicTrans", extTransV); - - extRot = Eigen::Map>(extRotV.data(), 3, 3); - extRPY = Eigen::Map>(extRPYV.data(), 3, 3); - extTrans = Eigen::Map>(extTransV.data(), 3, 1); - extQRPY = Eigen::Quaterniond(extRPY); - - declare_parameter("edgeThreshold", 1.0); - get_parameter("edgeThreshold", edgeThreshold); - declare_parameter("surfThreshold", 0.1); - get_parameter("surfThreshold", surfThreshold); - declare_parameter("edgeFeatureMinValidNum", 10); - get_parameter("edgeFeatureMinValidNum", edgeFeatureMinValidNum); - declare_parameter("surfFeatureMinValidNum", 100); - get_parameter("surfFeatureMinValidNum", surfFeatureMinValidNum); - - declare_parameter("odometrySurfLeafSize", 0.4); - get_parameter("odometrySurfLeafSize", odometrySurfLeafSize); - declare_parameter("mappingCornerLeafSize", 0.2); - get_parameter("mappingCornerLeafSize", mappingCornerLeafSize); - declare_parameter("mappingSurfLeafSize", 0.4); - get_parameter("mappingSurfLeafSize", mappingSurfLeafSize); - - declare_parameter("z_tollerance", 1000.0); - get_parameter("z_tollerance", z_tollerance); - declare_parameter("rotation_tollerance", 1000.0); - get_parameter("rotation_tollerance", rotation_tollerance); - - declare_parameter("numberOfCores", 4); - get_parameter("numberOfCores", numberOfCores); - declare_parameter("mappingProcessInterval", 0.15); - get_parameter("mappingProcessInterval", mappingProcessInterval); - - declare_parameter("surroundingkeyframeAddingDistThreshold", 1.0); - get_parameter("surroundingkeyframeAddingDistThreshold", surroundingkeyframeAddingDistThreshold); - declare_parameter("surroundingkeyframeAddingAngleThreshold", 0.2); - get_parameter("surroundingkeyframeAddingAngleThreshold", surroundingkeyframeAddingAngleThreshold); - declare_parameter("surroundingKeyframeDensity", 2.0); - get_parameter("surroundingKeyframeDensity", surroundingKeyframeDensity); - declare_parameter("surroundingKeyframeSearchRadius", 50.0); - get_parameter("surroundingKeyframeSearchRadius", surroundingKeyframeSearchRadius); - - declare_parameter("loopClosureEnableFlag", true); - get_parameter("loopClosureEnableFlag", loopClosureEnableFlag); - declare_parameter("loopClosureFrequency", 1.0); - get_parameter("loopClosureFrequency", loopClosureFrequency); - declare_parameter("surroundingKeyframeSize", 50); - get_parameter("surroundingKeyframeSize", surroundingKeyframeSize); - declare_parameter("historyKeyframeSearchRadius", 15.0); - get_parameter("historyKeyframeSearchRadius", historyKeyframeSearchRadius); - declare_parameter("historyKeyframeSearchTimeDiff", 30.0); - get_parameter("historyKeyframeSearchTimeDiff", historyKeyframeSearchTimeDiff); - declare_parameter("historyKeyframeSearchNum", 25); - get_parameter("historyKeyframeSearchNum", historyKeyframeSearchNum); - declare_parameter("historyKeyframeFitnessScore", 0.3); - get_parameter("historyKeyframeFitnessScore", historyKeyframeFitnessScore); - - declare_parameter("globalMapVisualizationSearchRadius", 1000.0); - get_parameter("globalMapVisualizationSearchRadius", globalMapVisualizationSearchRadius); - declare_parameter("globalMapVisualizationPoseDensity", 10.0); - get_parameter("globalMapVisualizationPoseDensity", globalMapVisualizationPoseDensity); - declare_parameter("globalMapVisualizationLeafSize", 1.0); - get_parameter("globalMapVisualizationLeafSize", globalMapVisualizationLeafSize); - - usleep(100); - } - - sensor_msgs::msg::Imu imuConverter(const sensor_msgs::msg::Imu& imu_in) - { - sensor_msgs::msg::Imu imu_out = imu_in; - // rotate acceleration - Eigen::Vector3d acc(imu_in.linear_acceleration.x, imu_in.linear_acceleration.y, imu_in.linear_acceleration.z); - acc = extRot * acc; - imu_out.linear_acceleration.x = acc.x(); - imu_out.linear_acceleration.y = acc.y(); - imu_out.linear_acceleration.z = acc.z(); - // rotate gyroscope - Eigen::Vector3d gyr(imu_in.angular_velocity.x, imu_in.angular_velocity.y, imu_in.angular_velocity.z); - gyr = extRot * gyr; - imu_out.angular_velocity.x = gyr.x(); - imu_out.angular_velocity.y = gyr.y(); - imu_out.angular_velocity.z = gyr.z(); - // rotate roll pitch yaw - Eigen::Quaterniond q_from(imu_in.orientation.w, imu_in.orientation.x, imu_in.orientation.y, imu_in.orientation.z); - Eigen::Quaterniond q_final = q_from * extQRPY; - imu_out.orientation.x = q_final.x(); - imu_out.orientation.y = q_final.y(); - imu_out.orientation.z = q_final.z(); - imu_out.orientation.w = q_final.w(); - - if (sqrt(q_final.x()*q_final.x() + q_final.y()*q_final.y() + q_final.z()*q_final.z() + q_final.w()*q_final.w()) < 0.1) - { - RCLCPP_ERROR(get_logger(), "Invalid quaternion, please use a 9-axis IMU!"); - rclcpp::shutdown(); - } - - return imu_out; - } -}; - - -sensor_msgs::msg::PointCloud2 publishCloud(rclcpp::Publisher::SharedPtr thisPub, pcl::PointCloud::Ptr thisCloud, rclcpp::Time thisStamp, std::string thisFrame) -{ - sensor_msgs::msg::PointCloud2 tempCloud; - pcl::toROSMsg(*thisCloud, tempCloud); - tempCloud.header.stamp = thisStamp; - tempCloud.header.frame_id = thisFrame; - if (thisPub->get_subscription_count() != 0) - thisPub->publish(tempCloud); - return tempCloud; -} - -template -double stamp2Sec(const T& stamp) -{ - return rclcpp::Time(stamp).seconds(); -} - - -template -void imuAngular2rosAngular(sensor_msgs::msg::Imu *thisImuMsg, T *angular_x, T *angular_y, T *angular_z) -{ - *angular_x = thisImuMsg->angular_velocity.x; - *angular_y = thisImuMsg->angular_velocity.y; - *angular_z = thisImuMsg->angular_velocity.z; -} - - -template -void imuAccel2rosAccel(sensor_msgs::msg::Imu *thisImuMsg, T *acc_x, T *acc_y, T *acc_z) -{ - *acc_x = thisImuMsg->linear_acceleration.x; - *acc_y = thisImuMsg->linear_acceleration.y; - *acc_z = thisImuMsg->linear_acceleration.z; -} - - -template // Converts IMU msg Quaternion to RPY -void imuRPY2rosRPY(sensor_msgs::msg::Imu *thisImuMsg, T *rosRoll, T *rosPitch, T *rosYaw) -{ - double imuRoll, imuPitch, imuYaw; - tf2::Quaternion orientation; - tf2::fromMsg(thisImuMsg->orientation, orientation); - tf2::Matrix3x3(orientation).getRPY(imuRoll, imuPitch, imuYaw); - - *rosRoll = imuRoll; - *rosPitch = imuPitch; - *rosYaw = imuYaw; -} - - -float pointDistance(PointType p) -{ - return sqrt(p.x*p.x + p.y*p.y + p.z*p.z); -} - - -float pointDistance(PointType p1, PointType p2) -{ - return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) + (p1.z-p2.z)*(p1.z-p2.z)); -} - -rmw_qos_profile_t qos_profile{ - RMW_QOS_POLICY_HISTORY_KEEP_LAST, - 1, - RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT, - RMW_QOS_POLICY_DURABILITY_VOLATILE, - RMW_QOS_DEADLINE_DEFAULT, - RMW_QOS_LIFESPAN_DEFAULT, - RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT, - RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT, - false -}; - -auto qos = rclcpp::QoS( - rclcpp::QoSInitialization( - qos_profile.history, - qos_profile.depth - ), - qos_profile); - -rmw_qos_profile_t qos_profile_imu{ - RMW_QOS_POLICY_HISTORY_KEEP_LAST, - 2000, - RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT, - RMW_QOS_POLICY_DURABILITY_VOLATILE, - RMW_QOS_DEADLINE_DEFAULT, - RMW_QOS_LIFESPAN_DEFAULT, - RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT, - RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT, - false -}; - -auto qos_imu = rclcpp::QoS( - rclcpp::QoSInitialization( - qos_profile_imu.history, - qos_profile_imu.depth - ), - qos_profile_imu); - -rmw_qos_profile_t qos_profile_lidar{ - RMW_QOS_POLICY_HISTORY_KEEP_LAST, - 5, - RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT, - RMW_QOS_POLICY_DURABILITY_VOLATILE, - RMW_QOS_DEADLINE_DEFAULT, - RMW_QOS_LIFESPAN_DEFAULT, - RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT, - RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT, - false -}; - -auto qos_lidar = rclcpp::QoS( - rclcpp::QoSInitialization( - qos_profile_lidar.history, - qos_profile_lidar.depth - ), - qos_profile_lidar); - -#endif diff --git a/src/mapping/lio_sam/launch/run.launch.py b/src/mapping/lio_sam/launch/run.launch.py deleted file mode 100755 index f897adf63..000000000 --- a/src/mapping/lio_sam/launch/run.launch.py +++ /dev/null @@ -1,80 +0,0 @@ -import os -from ament_index_python.packages import get_package_share_directory -from launch import LaunchDescription -from launch.actions import DeclareLaunchArgument -from launch.substitutions import LaunchConfiguration, Command -from launch_ros.actions import Node - - -def generate_launch_description(): - - share_dir = get_package_share_directory('lio_sam') - parameter_file = LaunchConfiguration('params_file') - xacro_path = os.path.join(share_dir, 'config', 'robot.urdf.xacro') - rviz_config_file = os.path.join(share_dir, 'config', 'rviz2.rviz') - - params_declare = DeclareLaunchArgument( - 'params_file', - default_value=os.path.join( - share_dir, 'config', 'params.yaml'), - description='FPath to the ROS2 parameters file to use.') - - print("urdf_file_name : {}".format(xacro_path)) - - return LaunchDescription([ - params_declare, - Node( - package='tf2_ros', # Fuse the map and odom frames - executable='static_transform_publisher', - arguments='0.0 0.0 0.0 1.0 0.0 0.0 map odom'.split(' '), - parameters=[parameter_file], - output='screen' - ), - Node( - package='robot_state_publisher', # Publish robot URDF - executable='robot_state_publisher', - name='robot_state_publisher', - output='screen', - parameters=[{ - 'robot_description': Command(['xacro', ' ', xacro_path]) - }] - ), - Node( - package='lio_sam', - executable='lio_sam_imuPreintegration', - name='lio_sam_imuPreintegration', - parameters=[parameter_file], - output='screen' - ), - Node( - package='lio_sam', - executable='lio_sam_imageProjection', - name='lio_sam_imageProjection', - parameters=[parameter_file], - output='screen' - ), - Node( - package='lio_sam', - executable='lio_sam_featureExtraction', - name='lio_sam_featureExtraction', - parameters=[parameter_file], - output='screen' - ), - Node( - package='lio_sam', - executable='lio_sam_mapOptimization', - name='lio_sam_mapOptimization', - parameters=[parameter_file], - output='screen' - ), - Node( - executable='lgsvl_bridge', - ) - # Node( - # package='rviz2', - # executable='rviz2', - # name='rviz2', - # arguments=['-d', rviz_config_file], - # output='screen' - # ) - ]) diff --git a/src/mapping/lio_sam/msg/CloudInfo.msg b/src/mapping/lio_sam/msg/CloudInfo.msg deleted file mode 100755 index 9060d13dc..000000000 --- a/src/mapping/lio_sam/msg/CloudInfo.msg +++ /dev/null @@ -1,29 +0,0 @@ -# Cloud Info -std_msgs/Header header - -int32[] start_ring_index -int32[] end_ring_index - -int32[] point_col_ind # point column index in range image -float32[] point_range # point range - -int64 imu_available -int64 odom_available - -# Attitude for LOAM initialization -float32 imu_roll_init -float32 imu_pitch_init -float32 imu_yaw_init - -# Initial guess from imu pre-integration -float32 initial_guess_x -float32 initial_guess_y -float32 initial_guess_z -float32 initial_guess_roll -float32 initial_guess_pitch -float32 initial_guess_yaw - -# Point cloud messages -sensor_msgs/PointCloud2 cloud_deskewed # original cloud deskewed -sensor_msgs/PointCloud2 cloud_corner # extracted corner feature -sensor_msgs/PointCloud2 cloud_surface # extracted surface feature diff --git a/src/mapping/lio_sam/package.xml b/src/mapping/lio_sam/package.xml deleted file mode 100755 index f83b88406..000000000 --- a/src/mapping/lio_sam/package.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - lio_sam - 1.0.0 - Lidar Odometry - - Tixiao Shan - - TODO - - Tixiao Shan - - ament_cmake - rosidl_default_generators - - rclcpp - rclpy - std_msgs - sensor_msgs - nav_msgs - geometry_msgs - std_srvs - tf2_geometry_msgs - tf2_sensor_msgs - tf2_eigen - tf2_ros - tf2 - OpenCV - PCL - GTSAM - Eigen - - rosidl_default_runtime - rclcpp - rclpy - std_msgs - sensor_msgs - nav_msgs - geometry_msgs - tf2_geometry_msgs - tf2_sensor_msgs - tf2_eigen - tf2_ros - tf2 - OpenCV - PCL - GTSAM - Eigen - - rosidl_interface_packages - - ament_lint_auto - - - - ament_cmake - - diff --git a/src/mapping/lio_sam/src/featureExtraction.cpp b/src/mapping/lio_sam/src/featureExtraction.cpp deleted file mode 100755 index 0a6af0365..000000000 --- a/src/mapping/lio_sam/src/featureExtraction.cpp +++ /dev/null @@ -1,281 +0,0 @@ -#include "utility.hpp" -#include "lio_sam/msg/cloud_info.hpp" - -struct smoothness_t{ - float value; - size_t ind; -}; - -struct by_value{ - bool operator()(smoothness_t const &left, smoothness_t const &right) { - return left.value < right.value; - } -}; - -class FeatureExtraction : public ParamServer -{ - -public: - - rclcpp::Subscription::SharedPtr subLaserCloudInfo; - - rclcpp::Publisher::SharedPtr pubLaserCloudInfo; - rclcpp::Publisher::SharedPtr pubCornerPoints; - rclcpp::Publisher::SharedPtr pubSurfacePoints; - - pcl::PointCloud::Ptr extractedCloud; - pcl::PointCloud::Ptr cornerCloud; - pcl::PointCloud::Ptr surfaceCloud; - - pcl::VoxelGrid downSizeFilter; - - lio_sam::msg::CloudInfo cloudInfo; - std_msgs::msg::Header cloudHeader; - - std::vector cloudSmoothness; - float *cloudCurvature; - int *cloudNeighborPicked; - int *cloudLabel; - - FeatureExtraction(const rclcpp::NodeOptions & options) : - ParamServer("lio_sam_featureExtraction", options) - { - subLaserCloudInfo = create_subscription( - "lio_sam/deskew/cloud_info", qos, - std::bind(&FeatureExtraction::laserCloudInfoHandler, this, std::placeholders::_1)); - - pubLaserCloudInfo = create_publisher( - "lio_sam/feature/cloud_info", qos); - pubCornerPoints = create_publisher( - "lio_sam/feature/cloud_corner", 1); - pubSurfacePoints = create_publisher( - "lio_sam/feature/cloud_surface", 1); - - initializationValue(); - } - - void initializationValue() - { - cloudSmoothness.resize(N_SCAN*Horizon_SCAN); - - downSizeFilter.setLeafSize(odometrySurfLeafSize, odometrySurfLeafSize, odometrySurfLeafSize); - - extractedCloud.reset(new pcl::PointCloud()); - cornerCloud.reset(new pcl::PointCloud()); - surfaceCloud.reset(new pcl::PointCloud()); - - cloudCurvature = new float[N_SCAN*Horizon_SCAN]; - cloudNeighborPicked = new int[N_SCAN*Horizon_SCAN]; - cloudLabel = new int[N_SCAN*Horizon_SCAN]; - } - - void laserCloudInfoHandler(const lio_sam::msg::CloudInfo::SharedPtr msgIn) - { - cloudInfo = *msgIn; // new cloud info - cloudHeader = msgIn->header; // new cloud header - pcl::fromROSMsg(msgIn->cloud_deskewed, *extractedCloud); // new cloud for extraction - - calculateSmoothness(); - - markOccludedPoints(); - - extractFeatures(); - - publishFeatureCloud(); - } - - void calculateSmoothness() - { - int cloudSize = extractedCloud->points.size(); - for (int i = 5; i < cloudSize - 5; i++) - { - float diffRange = cloudInfo.point_range[i-5] + cloudInfo.point_range[i-4] - + cloudInfo.point_range[i-3] + cloudInfo.point_range[i-2] - + cloudInfo.point_range[i-1] - cloudInfo.point_range[i] * 10 - + cloudInfo.point_range[i+1] + cloudInfo.point_range[i+2] - + cloudInfo.point_range[i+3] + cloudInfo.point_range[i+4] - + cloudInfo.point_range[i+5]; - - cloudCurvature[i] = diffRange*diffRange;//diffX * diffX + diffY * diffY + diffZ * diffZ; - - cloudNeighborPicked[i] = 0; - cloudLabel[i] = 0; - // cloudSmoothness for sorting - cloudSmoothness[i].value = cloudCurvature[i]; - cloudSmoothness[i].ind = i; - } - } - - void markOccludedPoints() - { - int cloudSize = extractedCloud->points.size(); - // mark occluded points and parallel beam points - for (int i = 5; i < cloudSize - 6; ++i) - { - // occluded points - float depth1 = cloudInfo.point_range[i]; - float depth2 = cloudInfo.point_range[i+1]; - int columnDiff = std::abs(int(cloudInfo.point_col_ind[i+1] - cloudInfo.point_col_ind[i])); - if (columnDiff < 10){ - // 10 pixel diff in range image - if (depth1 - depth2 > 0.3){ - cloudNeighborPicked[i - 5] = 1; - cloudNeighborPicked[i - 4] = 1; - cloudNeighborPicked[i - 3] = 1; - cloudNeighborPicked[i - 2] = 1; - cloudNeighborPicked[i - 1] = 1; - cloudNeighborPicked[i] = 1; - }else if (depth2 - depth1 > 0.3){ - cloudNeighborPicked[i + 1] = 1; - cloudNeighborPicked[i + 2] = 1; - cloudNeighborPicked[i + 3] = 1; - cloudNeighborPicked[i + 4] = 1; - cloudNeighborPicked[i + 5] = 1; - cloudNeighborPicked[i + 6] = 1; - } - } - // parallel beam - float diff1 = std::abs(float(cloudInfo.point_range[i-1] - cloudInfo.point_range[i])); - float diff2 = std::abs(float(cloudInfo.point_range[i+1] - cloudInfo.point_range[i])); - - if (diff1 > 0.02 * cloudInfo.point_range[i] && diff2 > 0.02 * cloudInfo.point_range[i]) - cloudNeighborPicked[i] = 1; - } - } - - void extractFeatures() - { - cornerCloud->clear(); - surfaceCloud->clear(); - - pcl::PointCloud::Ptr surfaceCloudScan(new pcl::PointCloud()); - pcl::PointCloud::Ptr surfaceCloudScanDS(new pcl::PointCloud()); - - for (int i = 0; i < N_SCAN; i++) - { - surfaceCloudScan->clear(); - - for (int j = 0; j < 6; j++) - { - - int sp = (cloudInfo.start_ring_index[i] * (6 - j) + cloudInfo.end_ring_index[i] * j) / 6; - int ep = (cloudInfo.start_ring_index[i] * (5 - j) + cloudInfo.end_ring_index[i] * (j + 1)) / 6 - 1; - - if (sp >= ep) - continue; - - std::sort(cloudSmoothness.begin()+sp, cloudSmoothness.begin()+ep, by_value()); - - int largestPickedNum = 0; - for (int k = ep; k >= sp; k--) - { - int ind = cloudSmoothness[k].ind; - if (cloudNeighborPicked[ind] == 0 && cloudCurvature[ind] > edgeThreshold) - { - largestPickedNum++; - if (largestPickedNum <= 20){ - cloudLabel[ind] = 1; - cornerCloud->push_back(extractedCloud->points[ind]); - } else { - break; - } - - cloudNeighborPicked[ind] = 1; - for (int l = 1; l <= 5; l++) - { - int columnDiff = std::abs(int(cloudInfo.point_col_ind[ind + l] - cloudInfo.point_col_ind[ind + l - 1])); - if (columnDiff > 10) - break; - cloudNeighborPicked[ind + l] = 1; - } - for (int l = -1; l >= -5; l--) - { - int columnDiff = std::abs(int(cloudInfo.point_col_ind[ind + l] - cloudInfo.point_col_ind[ind + l + 1])); - if (columnDiff > 10) - break; - cloudNeighborPicked[ind + l] = 1; - } - } - } - - for (int k = sp; k <= ep; k++) - { - int ind = cloudSmoothness[k].ind; - if (cloudNeighborPicked[ind] == 0 && cloudCurvature[ind] < surfThreshold) - { - - cloudLabel[ind] = -1; - cloudNeighborPicked[ind] = 1; - - for (int l = 1; l <= 5; l++) { - int columnDiff = std::abs(int(cloudInfo.point_col_ind[ind + l] - cloudInfo.point_col_ind[ind + l - 1])); - if (columnDiff > 10) - break; - - cloudNeighborPicked[ind + l] = 1; - } - for (int l = -1; l >= -5; l--) { - int columnDiff = std::abs(int(cloudInfo.point_col_ind[ind + l] - cloudInfo.point_col_ind[ind + l + 1])); - if (columnDiff > 10) - break; - - cloudNeighborPicked[ind + l] = 1; - } - } - } - - for (int k = sp; k <= ep; k++) - { - if (cloudLabel[k] <= 0){ - surfaceCloudScan->push_back(extractedCloud->points[k]); - } - } - } - - surfaceCloudScanDS->clear(); - downSizeFilter.setInputCloud(surfaceCloudScan); - downSizeFilter.filter(*surfaceCloudScanDS); - - *surfaceCloud += *surfaceCloudScanDS; - } - } - - void freeCloudInfoMemory() - { - cloudInfo.start_ring_index.clear(); - cloudInfo.end_ring_index.clear(); - cloudInfo.point_col_ind.clear(); - cloudInfo.point_range.clear(); - } - - void publishFeatureCloud() - { - // free cloud info memory - freeCloudInfoMemory(); - // save newly extracted features - cloudInfo.cloud_corner = publishCloud(pubCornerPoints, cornerCloud, cloudHeader.stamp, lidarFrame); - cloudInfo.cloud_surface = publishCloud(pubSurfacePoints, surfaceCloud, cloudHeader.stamp, lidarFrame); - // publish to mapOptimization - pubLaserCloudInfo->publish(cloudInfo); - } -}; - - -int main(int argc, char** argv) -{ - rclcpp::init(argc, argv); - rclcpp::NodeOptions options; - options.use_intra_process_comms(true); - rclcpp::executors::SingleThreadedExecutor exec; - - auto FE = std::make_shared(options); - - exec.add_node(FE); - - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "\033[1;32m----> Feature Extraction Started.\033[0m"); - - exec.spin(); - - rclcpp::shutdown(); - return 0; -} diff --git a/src/mapping/lio_sam/src/imageProjection.cpp b/src/mapping/lio_sam/src/imageProjection.cpp index d42723a11..7db3b5f68 100755 --- a/src/mapping/lio_sam/src/imageProjection.cpp +++ b/src/mapping/lio_sam/src/imageProjection.cpp @@ -5,29 +5,26 @@ struct VelodynePointXYZIRT { PCL_ADD_POINT4D // Adds XYZ and padding https://pointclouds.org/documentation/tutorials/adding_custom_ptype.html#id6 - PCL_ADD_INTENSITY; + PCL_ADD_INTENSITY; uint16_t ring; float time; EIGEN_MAKE_ALIGNED_OPERATOR_NEW } EIGEN_ALIGN16; -POINT_CLOUD_REGISTER_POINT_STRUCT (VelodynePointXYZIRT, - (float, x, x) (float, y, y) (float, z, z) (float, intensity, intensity) - (uint16_t, ring, ring) (float, time, time) -) +POINT_CLOUD_REGISTER_POINT_STRUCT(VelodynePointXYZIRT, + (float, x, x)(float, y, y)(float, z, z)(float, intensity, intensity)(uint16_t, ring, ring)(float, time, time)) struct RinglessVelodynePointXYZIT { PCL_ADD_POINT4D // Adds XYZ and padding https://pointclouds.org/documentation/tutorials/adding_custom_ptype.html#id6 - PCL_ADD_INTENSITY; + PCL_ADD_INTENSITY; float timestamp; // "timestamp" is what SVL calls it EIGEN_MAKE_ALIGNED_OPERATOR_NEW } EIGEN_ALIGN16; -POINT_CLOUD_REGISTER_POINT_STRUCT (RinglessVelodynePointXYZIT, - (float, x, x) (float, y, y) (float, z, z) (float, intensity, intensity) - (float, timestamp, timestamp) -) +POINT_CLOUD_REGISTER_POINT_STRUCT(RinglessVelodynePointXYZIT, + (float, x, x)(float, y, y)(float, z, z)(float, intensity, intensity)(float, timestamp, timestamp)) -struct OusterPointXYZIRT { +struct OusterPointXYZIRT +{ PCL_ADD_POINT4D; float intensity; uint32_t t; @@ -38,10 +35,7 @@ struct OusterPointXYZIRT { EIGEN_MAKE_ALIGNED_OPERATOR_NEW } EIGEN_ALIGN16; POINT_CLOUD_REGISTER_POINT_STRUCT(OusterPointXYZIRT, - (float, x, x) (float, y, y) (float, z, z) (float, intensity, intensity) - (uint32_t, t, t) (uint16_t, reflectivity, reflectivity) - (uint8_t, ring, ring) (uint16_t, noise, noise) (uint32_t, range, range) -) + (float, x, x)(float, y, y)(float, z, z)(float, intensity, intensity)(uint32_t, t, t)(uint16_t, reflectivity, reflectivity)(uint8_t, ring, ring)(uint16_t, noise, noise)(uint32_t, range, range)) // Use the Velodyne point format as a common representation using PointXYZIRT = VelodynePointXYZIRT; @@ -51,7 +45,6 @@ const int queueLength = 2000; // !!! This is big class ImageProjection : public ParamServer { private: - std::mutex imuLock; std::mutex odoLock; @@ -85,8 +78,8 @@ class ImageProjection : public ParamServer pcl::PointCloud::Ptr laserCloudIn; pcl::PointCloud::Ptr tmpOusterCloudIn; pcl::PointCloud::Ptr inputCloud; - pcl::PointCloud::Ptr fullCloud; - pcl::PointCloud::Ptr extractedCloud; + pcl::PointCloud::Ptr fullCloud; + pcl::PointCloud::Ptr extractedCloud; int deskewFlag; cv::Mat rangeMat; @@ -101,10 +94,8 @@ class ImageProjection : public ParamServer double timeScanEnd; std_msgs::msg::Header cloudHeader; - public: - ImageProjection(const rclcpp::NodeOptions & options) : - ParamServer("lio_sam_imageProjection", options), deskewFlag(0) + ImageProjection(const rclcpp::NodeOptions &options) : ParamServer("lio_sam_imageProjection", options), deskewFlag(0) { callbackGroupLidar = create_callback_group( rclcpp::CallbackGroupType::MutuallyExclusive); @@ -128,7 +119,7 @@ class ImageProjection : public ParamServer "/gps/odom", qos_imu, std::bind(&ImageProjection::odometryHandler, this, std::placeholders::_1), odomOpt); - subLaserCloud = create_subscription( // /lidar_front/points_raw + subLaserCloud = create_subscription( // /lidar_right/points_raw pointCloudTopic, qos_lidar, std::bind(&ImageProjection::cloudHandler, this, std::placeholders::_1), lidarOpt); @@ -152,13 +143,13 @@ class ImageProjection : public ParamServer fullCloud.reset(new pcl::PointCloud()); extractedCloud.reset(new pcl::PointCloud()); - fullCloud->points.resize(N_SCAN*Horizon_SCAN); + fullCloud->points.resize(N_SCAN * Horizon_SCAN); cloudInfo.start_ring_index.assign(N_SCAN, 0); cloudInfo.end_ring_index.assign(N_SCAN, 0); - cloudInfo.point_col_ind.assign(N_SCAN*Horizon_SCAN, 0); - cloudInfo.point_range.assign(N_SCAN*Horizon_SCAN, 0); + cloudInfo.point_col_ind.assign(N_SCAN * Horizon_SCAN, 0); + cloudInfo.point_range.assign(N_SCAN * Horizon_SCAN, 0); resetParameters(); } @@ -183,7 +174,7 @@ class ImageProjection : public ParamServer } } - ~ImageProjection(){} + ~ImageProjection() {} void imuHandler(const sensor_msgs::msg::Imu::SharedPtr imuMsg) { @@ -191,21 +182,25 @@ class ImageProjection : public ParamServer const int MAX_ACCEL = 10; - if (thisImu.linear_acceleration.x > MAX_ACCEL) { - RCLCPP_WARN_STREAM(get_logger(), "x linear accel out of bounds! Was "< MAX_ACCEL) + { + RCLCPP_WARN_STREAM(get_logger(), "x linear accel out of bounds! Was " << thisImu.linear_acceleration.x); thisImu.linear_acceleration.x = MAX_ACCEL; } - if (thisImu.linear_acceleration.x < MAX_ACCEL*-1) { - RCLCPP_WARN_STREAM(get_logger(), "x linear accel out of bounds! Was "< MAX_ACCEL) { - RCLCPP_WARN_STREAM(get_logger(), "y linear accel out of bounds! Was "< MAX_ACCEL) + { + RCLCPP_WARN_STREAM(get_logger(), "y linear accel out of bounds! Was " << thisImu.linear_acceleration.y); thisImu.linear_acceleration.y = MAX_ACCEL; } - if (thisImu.linear_acceleration.y < MAX_ACCEL*-1) { - RCLCPP_WARN_STREAM(get_logger(), "y linear accel out of bounds! Was "< MAX_ACCEL) { // RCLCPP_WARN_STREAM(get_logger(), "z linear accel out of bounds! Was "< lock2(odoLock); - odomQueue.push_back(*odometryMsg); // Add + odomQueue.push_back(*odometryMsg); // Add } void cloudHandler(const sensor_msgs::msg::PointCloud2::SharedPtr laserCloudMsg) { - // Fails if cloudqueue is <= 2 or + // Fails if cloudqueue is <= 2 or if (!cachePointCloud(laserCloudMsg)) return; @@ -291,7 +285,7 @@ class ImageProjection : public ParamServer resetParameters(); } - bool cachePointCloud(const sensor_msgs::msg::PointCloud2::SharedPtr& laserCloudMsg) + bool cachePointCloud(const sensor_msgs::msg::PointCloud2::SharedPtr &laserCloudMsg) { // cache point cloud cloudQueue.push_back(*laserCloudMsg); @@ -300,7 +294,7 @@ class ImageProjection : public ParamServer // convert cloud currentCloudMsg = std::move(cloudQueue.front()); // Take cloud from front - cloudQueue.pop_front(); // Delete front + cloudQueue.pop_front(); // Delete front if (sensor == SensorType::VELODYNE) { pcl::moveFromROSMsg(currentCloudMsg, *laserCloudIn); // Convert from ROS PointCloud2 to pcl::PointCloud::Ptr @@ -327,7 +321,8 @@ class ImageProjection : public ParamServer // } // Here we cover for a lack of ring data by adding some fake (manually calculated) values - else if (sensor == SensorType::RINGLESS_VLP_16) { + else if (sensor == SensorType::RINGLESS_VLP_16) + { // pcl::PointCloud::Ptr inputCloud; // RCLCPP_INFO(get_logger(),"A"); pcl::moveFromROSMsg(currentCloudMsg, *inputCloud); @@ -347,21 +342,22 @@ class ImageProjection : public ParamServer dst.y = src.y; dst.z = src.z; dst.intensity = src.intensity; - + dst.time = src.timestamp; // Fake a ring value // Ring value is from 0 to 15, with 0 being lowest and 15 being highest - + // Find pitch of point relative to sensor height, = atan(x/sqrt(x^2+y^2)) - double pitch_degrees = atan2(src.z, sqrt(pow(src.x,2)+pow(src.y,2))) * 180/3.14159265; + double pitch_degrees = atan2(src.z, sqrt(pow(src.x, 2) + pow(src.y, 2))) * 180 / 3.14159265; // Find pitch of point from bottom of FOV - double pitch_from_bottom = pitch_degrees+fov_below_middle_deg; + double pitch_from_bottom = pitch_degrees + fov_below_middle_deg; // RCLCPP_DEBUG_STREAM(get_logger(), "Center ("<[0,15] - int ring_number = round((pitch_from_bottom/fov_deg)*16); // This will always round DOWN. + int ring_number = round((pitch_from_bottom / fov_deg) * 16); // This will always round DOWN. // int ring_number = floor(pitch_from_bottom * (ring_count) / fov_deg); // RCLCPP_INFO_STREAM(get_logger(), "("< atan("<=(ring_count-1)) { + if (ring_number >= (ring_count - 1)) + { // RCLCPP_ERROR_STREAM(get_logger(), "Ring number "<size(); i++) // { // auto &dst = laserCloudIn->points[i]; - // RCLCPP_INFO_STREAM(get_logger(), "("<x + transBt(0,1) * point->y + transBt(0,2) * point->z + transBt(0,3); - newPoint.y = transBt(1,0) * point->x + transBt(1,1) * point->y + transBt(1,2) * point->z + transBt(1,3); - newPoint.z = transBt(2,0) * point->x + transBt(2,1) * point->y + transBt(2,2) * point->z + transBt(2,3); + newPoint.x = transBt(0, 0) * point->x + transBt(0, 1) * point->y + transBt(0, 2) * point->z + transBt(0, 3); + newPoint.y = transBt(1, 0) * point->x + transBt(1, 1) * point->y + transBt(1, 2) * point->z + transBt(1, 3); + newPoint.z = transBt(2, 0) * point->x + transBt(2, 1) * point->y + transBt(2, 2) * point->z + transBt(2, 3); newPoint.intensity = point->intensity; return newPoint; @@ -699,8 +702,8 @@ class ImageProjection : public ParamServer float horizonAngle = atan2(thisPoint.x, thisPoint.y) * 180 / M_PI; - static float ang_res_x = 360.0/float(Horizon_SCAN); - int columnIdn = -round((horizonAngle-90.0)/ang_res_x) + Horizon_SCAN/2; + static float ang_res_x = 360.0 / float(Horizon_SCAN); + int columnIdn = -round((horizonAngle - 90.0) / ang_res_x) + Horizon_SCAN / 2; if (columnIdn >= Horizon_SCAN) columnIdn -= Horizon_SCAN; @@ -728,31 +731,31 @@ class ImageProjection : public ParamServer cloudInfo.start_ring_index[i] = count - 1 + 5; for (int j = 0; j < Horizon_SCAN; ++j) { - if (rangeMat.at(i,j) != FLT_MAX) + if (rangeMat.at(i, j) != FLT_MAX) { // mark the points' column index for marking occlusion later cloudInfo.point_col_ind[count] = j; // save range info - cloudInfo.point_range[count] = rangeMat.at(i,j); + cloudInfo.point_range[count] = rangeMat.at(i, j); // save extracted cloud - extractedCloud->push_back(fullCloud->points[j + i*Horizon_SCAN]); + extractedCloud->push_back(fullCloud->points[j + i * Horizon_SCAN]); // size of extracted cloud ++count; } } - cloudInfo.end_ring_index[i] = count -1 - 5; + cloudInfo.end_ring_index[i] = count - 1 - 5; } } - + void publishClouds() { cloudInfo.header = cloudHeader; - cloudInfo.cloud_deskewed = publishCloud(pubExtractedCloud, extractedCloud, cloudHeader.stamp, lidarFrame); + cloudInfo.cloud_deskewed = publishCloud(pubExtractedCloud, extractedCloud, cloudHeader.stamp, lidarFrame); pubLaserCloudInfo->publish(cloudInfo); } }; -int main(int argc, char** argv) +int main(int argc, char **argv) { rclcpp::init(argc, argv); diff --git a/src/mapping/lio_sam/src/imuPreintegration.cpp b/src/mapping/lio_sam/src/imuPreintegration.cpp deleted file mode 100755 index 212767810..000000000 --- a/src/mapping/lio_sam/src/imuPreintegration.cpp +++ /dev/null @@ -1,564 +0,0 @@ -#include "utility.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using gtsam::symbol_shorthand::X; // Pose3 (x,y,z,r,p,y) -using gtsam::symbol_shorthand::V; // Vel (xdot,ydot,zdot) -using gtsam::symbol_shorthand::B; // Bias (ax,ay,az,gx,gy,gz) - -class TransformFusion : public ParamServer -{ -public: - std::mutex mtx; - - rclcpp::Subscription::SharedPtr subImuOdometry; - rclcpp::Subscription::SharedPtr subLaserOdometry; - - rclcpp::CallbackGroup::SharedPtr callbackGroupImuOdometry; - rclcpp::CallbackGroup::SharedPtr callbackGroupLaserOdometry; - - rclcpp::Publisher::SharedPtr pubImuOdometry; - rclcpp::Publisher::SharedPtr pubImuPath; - - Eigen::Isometry3d lidarOdomAffine; - Eigen::Isometry3d imuOdomAffineFront; - Eigen::Isometry3d imuOdomAffineBack; - - std::shared_ptr tfBuffer; - std::shared_ptr tfBroadcaster; - std::shared_ptr tfListener; - tf2::Stamped lidar2Baselink; - - double lidarOdomTime = -1; - deque imuOdomQueue; - - TransformFusion(const rclcpp::NodeOptions & options) : ParamServer("lio_sam_transformFusion", options) - { - tfBuffer = std::make_shared(get_clock()); - tfListener = std::make_shared(*tfBuffer); - - callbackGroupImuOdometry = create_callback_group( - rclcpp::CallbackGroupType::MutuallyExclusive); - callbackGroupLaserOdometry = create_callback_group( - rclcpp::CallbackGroupType::MutuallyExclusive); - - auto imuOdomOpt = rclcpp::SubscriptionOptions(); - imuOdomOpt.callback_group = callbackGroupImuOdometry; - auto laserOdomOpt = rclcpp::SubscriptionOptions(); - laserOdomOpt.callback_group = callbackGroupLaserOdometry; - - subLaserOdometry = create_subscription( - "lio_sam/mapping/odometry", qos, - std::bind(&TransformFusion::lidarOdometryHandler, this, std::placeholders::_1), - laserOdomOpt); - subImuOdometry = create_subscription( - "/gps/odom", qos_imu, - std::bind(&TransformFusion::imuOdometryHandler, this, std::placeholders::_1), - imuOdomOpt); - - pubImuOdometry = create_publisher(odomTopic, qos_imu); - pubImuPath = create_publisher("lio_sam/imu/path", qos); - - tfBroadcaster = std::make_unique(this); - } - - Eigen::Isometry3d odom2affine(nav_msgs::msg::Odometry odom) - { - tf2::Transform t; - tf2::fromMsg(odom.pose.pose, t); - return tf2::transformToEigen(tf2::toMsg(t)); - } - - void lidarOdometryHandler(const nav_msgs::msg::Odometry::SharedPtr odomMsg) - { - std::lock_guard lock(mtx); - - lidarOdomAffine = odom2affine(*odomMsg); - - lidarOdomTime = stamp2Sec(odomMsg->header.stamp); - } - - void imuOdometryHandler(const nav_msgs::msg::Odometry::SharedPtr odomMsg) - { - std::lock_guard lock(mtx); - - imuOdomQueue.push_back(*odomMsg); - - // get latest odometry (at current IMU stamp) - if (lidarOdomTime == -1) - return; - while (!imuOdomQueue.empty()) - { - if (stamp2Sec(imuOdomQueue.front().header.stamp) <= lidarOdomTime) - imuOdomQueue.pop_front(); - else - break; - } - Eigen::Isometry3d imuOdomAffineFront = odom2affine(imuOdomQueue.front()); - Eigen::Isometry3d imuOdomAffineBack = odom2affine(imuOdomQueue.back()); - Eigen::Isometry3d imuOdomAffineIncre = imuOdomAffineFront.inverse() * imuOdomAffineBack; - Eigen::Isometry3d imuOdomAffineLast = lidarOdomAffine * imuOdomAffineIncre; - auto t = tf2::eigenToTransform(imuOdomAffineLast); - tf2::Stamped tCur; - tf2::convert(t, tCur); - - // publish latest odometry - nav_msgs::msg::Odometry laserOdometry = imuOdomQueue.back(); - laserOdometry.pose.pose.position.x = t.transform.translation.x; - laserOdometry.pose.pose.position.y = t.transform.translation.y; - laserOdometry.pose.pose.position.z = t.transform.translation.z; - laserOdometry.pose.pose.orientation = t.transform.rotation; - pubImuOdometry->publish(laserOdometry); - - // publish tf - if(lidarFrame != baselinkFrame) - { - try - { - tf2::fromMsg(tfBuffer->lookupTransform( - lidarFrame, baselinkFrame, rclcpp::Time(-10)), lidar2Baselink); - } - catch (tf2::TransformException ex) - { - RCLCPP_ERROR(get_logger(), "%s", ex.what()); - } - tf2::Stamped tb( - tCur * lidar2Baselink, tf2_ros::fromMsg(odomMsg->header.stamp), odometryFrame); - tCur = tb; - } - geometry_msgs::msg::TransformStamped ts; - tf2::convert(tCur, ts); - ts.child_frame_id = baselinkFrame; - tfBroadcaster->sendTransform(ts); - - // publish IMU path - static nav_msgs::msg::Path imuPath; - static double last_path_time = -1; - double imuTime = stamp2Sec(imuOdomQueue.back().header.stamp); - if (imuTime - last_path_time > 0.1) - { - last_path_time = imuTime; - geometry_msgs::msg::PoseStamped pose_stamped; - pose_stamped.header.stamp = imuOdomQueue.back().header.stamp; - pose_stamped.header.frame_id = odometryFrame; - pose_stamped.pose = laserOdometry.pose.pose; - imuPath.poses.push_back(pose_stamped); - while(!imuPath.poses.empty() && stamp2Sec(imuPath.poses.front().header.stamp) < lidarOdomTime - 1.0) - imuPath.poses.erase(imuPath.poses.begin()); - if (pubImuPath->get_subscription_count() != 0) - { - imuPath.header.stamp = imuOdomQueue.back().header.stamp; - imuPath.header.frame_id = odometryFrame; - pubImuPath->publish(imuPath); - } - } - } -}; - -class IMUPreintegration : public ParamServer -{ -public: - - std::mutex mtx; - - rclcpp::Subscription::SharedPtr subImu; - rclcpp::Subscription::SharedPtr subOdometry; - rclcpp::Publisher::SharedPtr pubImuOdometry; - - rclcpp::CallbackGroup::SharedPtr callbackGroupImu; - rclcpp::CallbackGroup::SharedPtr callbackGroupOdom; - - bool systemInitialized = false; - - gtsam::noiseModel::Diagonal::shared_ptr priorPoseNoise; - gtsam::noiseModel::Diagonal::shared_ptr priorVelNoise; - gtsam::noiseModel::Diagonal::shared_ptr priorBiasNoise; - gtsam::noiseModel::Diagonal::shared_ptr correctionNoise; - gtsam::noiseModel::Diagonal::shared_ptr correctionNoise2; - gtsam::Vector noiseModelBetweenBias; - - - gtsam::PreintegratedImuMeasurements *imuIntegratorOpt_; - gtsam::PreintegratedImuMeasurements *imuIntegratorImu_; - - std::deque imuQueOpt; - std::deque imuQueImu; - - gtsam::Pose3 prevPose_; - gtsam::Vector3 prevVel_; - gtsam::NavState prevState_; - gtsam::imuBias::ConstantBias prevBias_; - - gtsam::NavState prevStateOdom; - gtsam::imuBias::ConstantBias prevBiasOdom; - - bool doneFirstOpt = false; - double lastImuT_imu = -1; - double lastImuT_opt = -1; - - gtsam::ISAM2 optimizer; - gtsam::NonlinearFactorGraph graphFactors; - gtsam::Values graphValues; - - const double delta_t = 0; - - int key = 1; - - gtsam::Pose3 imu2Lidar = gtsam::Pose3(gtsam::Rot3(1, 0, 0, 0), gtsam::Point3(-extTrans.x(), -extTrans.y(), -extTrans.z())); - gtsam::Pose3 lidar2Imu = gtsam::Pose3(gtsam::Rot3(1, 0, 0, 0), gtsam::Point3(extTrans.x(), extTrans.y(), extTrans.z())); - - IMUPreintegration(const rclcpp::NodeOptions & options) : - ParamServer("lio_sam_imu_preintegration", options) - { - callbackGroupImu = create_callback_group( - rclcpp::CallbackGroupType::MutuallyExclusive); - callbackGroupOdom = create_callback_group( - rclcpp::CallbackGroupType::MutuallyExclusive); - - auto imuOpt = rclcpp::SubscriptionOptions(); - imuOpt.callback_group = callbackGroupImu; - auto odomOpt = rclcpp::SubscriptionOptions(); - odomOpt.callback_group = callbackGroupOdom; - - subImu = create_subscription( - imuTopic, qos_imu, - std::bind(&IMUPreintegration::imuHandler, this, std::placeholders::_1), - imuOpt); - subOdometry = create_subscription( - "lio_sam/mapping/odometry_incremental", qos, - std::bind(&IMUPreintegration::odometryHandler, this, std::placeholders::_1), - odomOpt); - - pubImuOdometry = create_publisher(odomTopic+"_incremental", qos_imu); - - boost::shared_ptr p = gtsam::PreintegrationParams::MakeSharedU(imuGravity); - p->accelerometerCovariance = gtsam::Matrix33::Identity(3,3) * pow(imuAccNoise, 2); // acc white noise in continuous - p->gyroscopeCovariance = gtsam::Matrix33::Identity(3,3) * pow(imuGyrNoise, 2); // gyro white noise in continuous - p->integrationCovariance = gtsam::Matrix33::Identity(3,3) * pow(1e-4, 2); // error committed in integrating position from velocities - gtsam::imuBias::ConstantBias prior_imu_bias((gtsam::Vector(6) << 0, 0, 0, 0, 0, 0).finished());; // assume zero initial bias - - priorPoseNoise = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 1e-2, 1e-2, 1e-2, 1e-2, 1e-2, 1e-2).finished()); // rad,rad,rad,m, m, m - priorVelNoise = gtsam::noiseModel::Isotropic::Sigma(3, 1e4); // m/s - priorBiasNoise = gtsam::noiseModel::Isotropic::Sigma(6, 1e-3); // 1e-2 ~ 1e-3 seems to be good - correctionNoise = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 0.05, 0.05, 0.05, 0.1, 0.1, 0.1).finished()); // rad,rad,rad,m, m, m - correctionNoise2 = gtsam::noiseModel::Diagonal::Sigmas((gtsam::Vector(6) << 1, 1, 1, 1, 1, 1).finished()); // rad,rad,rad,m, m, m - noiseModelBetweenBias = (gtsam::Vector(6) << imuAccBiasN, imuAccBiasN, imuAccBiasN, imuGyrBiasN, imuGyrBiasN, imuGyrBiasN).finished(); - - imuIntegratorImu_ = new gtsam::PreintegratedImuMeasurements(p, prior_imu_bias); // setting up the IMU integration for IMU message thread - imuIntegratorOpt_ = new gtsam::PreintegratedImuMeasurements(p, prior_imu_bias); // setting up the IMU integration for optimization - } - - void resetOptimization() - { - gtsam::ISAM2Params optParameters; - optParameters.relinearizeThreshold = 0.1; - optParameters.relinearizeSkip = 1; - optimizer = gtsam::ISAM2(optParameters); - - gtsam::NonlinearFactorGraph newGraphFactors; - graphFactors = newGraphFactors; - - gtsam::Values NewGraphValues; - graphValues = NewGraphValues; - } - - void resetParams() - { - lastImuT_imu = -1; - doneFirstOpt = false; - systemInitialized = false; - } - - void odometryHandler(const nav_msgs::msg::Odometry::SharedPtr odomMsg) - { - std::lock_guard lock(mtx); - - double currentCorrectionTime = stamp2Sec(odomMsg->header.stamp); - - // make sure we have imu data to integrate - if (imuQueOpt.empty()) - return; - - float p_x = odomMsg->pose.pose.position.x; - float p_y = odomMsg->pose.pose.position.y; - float p_z = odomMsg->pose.pose.position.z; - float r_x = odomMsg->pose.pose.orientation.x; - float r_y = odomMsg->pose.pose.orientation.y; - float r_z = odomMsg->pose.pose.orientation.z; - float r_w = odomMsg->pose.pose.orientation.w; - bool degenerate = (int)odomMsg->pose.covariance[0] == 1 ? true : false; - gtsam::Pose3 lidarPose = gtsam::Pose3(gtsam::Rot3::Quaternion(r_w, r_x, r_y, r_z), gtsam::Point3(p_x, p_y, p_z)); - - - // 0. initialize system - if (systemInitialized == false) - { - resetOptimization(); - - // pop old IMU message - while (!imuQueOpt.empty()) - { - if (stamp2Sec(imuQueOpt.front().header.stamp) < currentCorrectionTime - delta_t) - { - lastImuT_opt = stamp2Sec(imuQueOpt.front().header.stamp); - imuQueOpt.pop_front(); - } - else - break; - } - // initial pose - prevPose_ = lidarPose.compose(lidar2Imu); - gtsam::PriorFactor priorPose(X(0), prevPose_, priorPoseNoise); - graphFactors.add(priorPose); - // initial velocity - prevVel_ = gtsam::Vector3(0, 0, 0); - gtsam::PriorFactor priorVel(V(0), prevVel_, priorVelNoise); - graphFactors.add(priorVel); - // initial bias - prevBias_ = gtsam::imuBias::ConstantBias(); - gtsam::PriorFactor priorBias(B(0), prevBias_, priorBiasNoise); - graphFactors.add(priorBias); - // add values - graphValues.insert(X(0), prevPose_); - graphValues.insert(V(0), prevVel_); - graphValues.insert(B(0), prevBias_); - // optimize once - optimizer.update(graphFactors, graphValues); - graphFactors.resize(0); - graphValues.clear(); - - imuIntegratorImu_->resetIntegrationAndSetBias(prevBias_); - imuIntegratorOpt_->resetIntegrationAndSetBias(prevBias_); - - key = 1; - systemInitialized = true; - return; - } - - - // reset graph for speed - if (key == 100) - { - // get updated noise before reset - gtsam::noiseModel::Gaussian::shared_ptr updatedPoseNoise = gtsam::noiseModel::Gaussian::Covariance(optimizer.marginalCovariance(X(key-1))); - gtsam::noiseModel::Gaussian::shared_ptr updatedVelNoise = gtsam::noiseModel::Gaussian::Covariance(optimizer.marginalCovariance(V(key-1))); - gtsam::noiseModel::Gaussian::shared_ptr updatedBiasNoise = gtsam::noiseModel::Gaussian::Covariance(optimizer.marginalCovariance(B(key-1))); - // reset graph - resetOptimization(); - // add pose - gtsam::PriorFactor priorPose(X(0), prevPose_, updatedPoseNoise); - graphFactors.add(priorPose); - // add velocity - gtsam::PriorFactor priorVel(V(0), prevVel_, updatedVelNoise); - graphFactors.add(priorVel); - // add bias - gtsam::PriorFactor priorBias(B(0), prevBias_, updatedBiasNoise); - graphFactors.add(priorBias); - // add values - graphValues.insert(X(0), prevPose_); - graphValues.insert(V(0), prevVel_); - graphValues.insert(B(0), prevBias_); - // optimize once - optimizer.update(graphFactors, graphValues); - graphFactors.resize(0); - graphValues.clear(); - - key = 1; - } - - - // 1. integrate imu data and optimize - while (!imuQueOpt.empty()) - { - // pop and integrate imu data that is between two optimizations - sensor_msgs::msg::Imu *thisImu = &imuQueOpt.front(); - double imuTime = stamp2Sec(thisImu->header.stamp); - - if (imuTime < currentCorrectionTime - delta_t) - { - double dt = (lastImuT_opt < 0) ? (1.0 / 500.0) : (imuTime - lastImuT_opt); - imuIntegratorOpt_->integrateMeasurement( - gtsam::Vector3(thisImu->linear_acceleration.x, thisImu->linear_acceleration.y, thisImu->linear_acceleration.z), - gtsam::Vector3(thisImu->angular_velocity.x, thisImu->angular_velocity.y, thisImu->angular_velocity.z), dt); - - lastImuT_opt = imuTime; - imuQueOpt.pop_front(); - } - else - break; - } - // add imu factor to graph - const gtsam::PreintegratedImuMeasurements& preint_imu = dynamic_cast(*imuIntegratorOpt_); - gtsam::ImuFactor imu_factor(X(key - 1), V(key - 1), X(key), V(key), B(key - 1), preint_imu); - graphFactors.add(imu_factor); - // add imu bias between factor - graphFactors.add(gtsam::BetweenFactor(B(key - 1), B(key), gtsam::imuBias::ConstantBias(), - gtsam::noiseModel::Diagonal::Sigmas(sqrt(imuIntegratorOpt_->deltaTij()) * noiseModelBetweenBias))); - // add pose factor - gtsam::Pose3 curPose = lidarPose.compose(lidar2Imu); - gtsam::PriorFactor pose_factor(X(key), curPose, degenerate ? correctionNoise2 : correctionNoise); - graphFactors.add(pose_factor); - // insert predicted values - gtsam::NavState propState_ = imuIntegratorOpt_->predict(prevState_, prevBias_); - graphValues.insert(X(key), propState_.pose()); - graphValues.insert(V(key), propState_.v()); - graphValues.insert(B(key), prevBias_); - // optimize - optimizer.update(graphFactors, graphValues); - optimizer.update(); - graphFactors.resize(0); - graphValues.clear(); - // Overwrite the beginning of the preintegration for the next step. - gtsam::Values result = optimizer.calculateEstimate(); - prevPose_ = result.at(X(key)); - prevVel_ = result.at(V(key)); - prevState_ = gtsam::NavState(prevPose_, prevVel_); - prevBias_ = result.at(B(key)); - // Reset the optimization preintegration object. - imuIntegratorOpt_->resetIntegrationAndSetBias(prevBias_); - // check optimization - if (failureDetection(prevVel_, prevBias_)) - { - resetParams(); - return; - } - - - // 2. after optiization, re-propagate imu odometry preintegration - prevStateOdom = prevState_; - prevBiasOdom = prevBias_; - // first pop imu message older than current correction data - double lastImuQT = -1; - while (!imuQueImu.empty() && stamp2Sec(imuQueImu.front().header.stamp) < currentCorrectionTime - delta_t) - { - lastImuQT = stamp2Sec(imuQueImu.front().header.stamp); - imuQueImu.pop_front(); - } - // repropogate - if (!imuQueImu.empty()) - { - // reset bias use the newly optimized bias - imuIntegratorImu_->resetIntegrationAndSetBias(prevBiasOdom); - // integrate imu message from the beginning of this optimization - for (int i = 0; i < (int)imuQueImu.size(); ++i) - { - sensor_msgs::msg::Imu *thisImu = &imuQueImu[i]; - double imuTime = stamp2Sec(thisImu->header.stamp); - double dt = (lastImuQT < 0) ? (1.0 / 500.0) :(imuTime - lastImuQT); - - imuIntegratorImu_->integrateMeasurement(gtsam::Vector3(thisImu->linear_acceleration.x, thisImu->linear_acceleration.y, thisImu->linear_acceleration.z), - gtsam::Vector3(thisImu->angular_velocity.x, thisImu->angular_velocity.y, thisImu->angular_velocity.z), dt); - lastImuQT = imuTime; - } - } - - ++key; - doneFirstOpt = true; - } - - bool failureDetection(const gtsam::Vector3& velCur, const gtsam::imuBias::ConstantBias& biasCur) - { - Eigen::Vector3f vel(velCur.x(), velCur.y(), velCur.z()); - if (vel.norm() > 40) - { - RCLCPP_WARN_STREAM(get_logger(), "Large velocity, reset IMU-preintegration! v="< 1.0 || bg.norm() > 1.0) - { - RCLCPP_WARN(get_logger(), "Large bias, reset IMU-preintegration!"); - return true; - } - - return false; - } - - void imuHandler(const sensor_msgs::msg::Imu::SharedPtr imu_raw) - { - std::lock_guard lock(mtx); - - sensor_msgs::msg::Imu thisImu = imuConverter(*imu_raw); - - imuQueOpt.push_back(thisImu); - imuQueImu.push_back(thisImu); - - if (doneFirstOpt == false) - return; - - double imuTime = stamp2Sec(thisImu.header.stamp); - double dt = (lastImuT_imu < 0) ? (1.0 / 500.0) : (imuTime - lastImuT_imu); - lastImuT_imu = imuTime; - - // integrate this single imu message - imuIntegratorImu_->integrateMeasurement(gtsam::Vector3(thisImu.linear_acceleration.x, thisImu.linear_acceleration.y, thisImu.linear_acceleration.z), - gtsam::Vector3(thisImu.angular_velocity.x, thisImu.angular_velocity.y, thisImu.angular_velocity.z), dt); - - // predict odometry - gtsam::NavState currentState = imuIntegratorImu_->predict(prevStateOdom, prevBiasOdom); - - // publish odometry - auto odometry = nav_msgs::msg::Odometry(); - odometry.header.stamp = thisImu.header.stamp; - odometry.header.frame_id = odometryFrame; - odometry.child_frame_id = "odom_imu"; - - // transform imu pose to ldiar - gtsam::Pose3 imuPose = gtsam::Pose3(currentState.quaternion(), currentState.position()); - gtsam::Pose3 lidarPose = imuPose.compose(imu2Lidar); - - odometry.pose.pose.position.x = lidarPose.translation().x(); - odometry.pose.pose.position.y = lidarPose.translation().y(); - odometry.pose.pose.position.z = lidarPose.translation().z(); - odometry.pose.pose.orientation.x = lidarPose.rotation().toQuaternion().x(); - odometry.pose.pose.orientation.y = lidarPose.rotation().toQuaternion().y(); - odometry.pose.pose.orientation.z = lidarPose.rotation().toQuaternion().z(); - odometry.pose.pose.orientation.w = lidarPose.rotation().toQuaternion().w(); - - odometry.twist.twist.linear.x = currentState.velocity().x(); - odometry.twist.twist.linear.y = currentState.velocity().y(); - odometry.twist.twist.linear.z = currentState.velocity().z(); - odometry.twist.twist.angular.x = thisImu.angular_velocity.x + prevBiasOdom.gyroscope().x(); - odometry.twist.twist.angular.y = thisImu.angular_velocity.y + prevBiasOdom.gyroscope().y(); - odometry.twist.twist.angular.z = thisImu.angular_velocity.z + prevBiasOdom.gyroscope().z(); - pubImuOdometry->publish(odometry); - } -}; - - -int main(int argc, char** argv) -{ - rclcpp::init(argc, argv); - - rclcpp::NodeOptions options; - options.use_intra_process_comms(true); - rclcpp::executors::MultiThreadedExecutor e; - - auto ImuP = std::make_shared(options); - auto TF = std::make_shared(options); - e.add_node(ImuP); - e.add_node(TF); - - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "\033[1;32m----> IMU Preintegration Started.\033[0m"); - - e.spin(); - - rclcpp::shutdown(); - return 0; -} diff --git a/src/mapping/lio_sam/src/mapOptmization.cpp b/src/mapping/lio_sam/src/mapOptmization.cpp deleted file mode 100755 index db4726011..000000000 --- a/src/mapping/lio_sam/src/mapOptmization.cpp +++ /dev/null @@ -1,1827 +0,0 @@ -#include "utility.hpp" -#include "lio_sam/msg/cloud_info.hpp" - -#include // GTSAM is a library for factor graphs and Bayes optimization. Used for loop closure, GPS correction, etc. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#define ROLL_TOLERANCE_RADS 0.35 // ~35 degrees -#define PITCH_TOLERANCE_RADS 0.35 // ~35 degrees - -using namespace gtsam; - -// symbol_shorthand is part of gtsam. See http://docs.ros.org/en/kinetic/api/gtsam/html/namespacegtsam_1_1symbol__shorthand.html -using symbol_shorthand::X; // Pose3 (x,y,z,r,p,y) -using symbol_shorthand::V; // Vel (xdot,ydot,zdot) -using symbol_shorthand::B; // Bias (ax,ay,az,gx,gy,gz) -using symbol_shorthand::G; // GPS pose - -/* - * A point cloud type that has 6D pose info ([x,y,z,roll,pitch,yaw] intensity is time stamp) - */ -struct PointXYZIRPYT -{ - PCL_ADD_POINT4D // Do we need a semicolon here? - PCL_ADD_INTENSITY; // preferred way of adding a XYZ+padding... what??? - float roll; - float pitch; - float yaw; - double time; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW // make sure our new allocators are aligned -} EIGEN_ALIGN16; // enforce SSE padding for correct memory alignment - -POINT_CLOUD_REGISTER_POINT_STRUCT (PointXYZIRPYT, - (float, x, x) (float, y, y) - (float, z, z) (float, intensity, intensity) - (float, roll, roll) (float, pitch, pitch) (float, yaw, yaw) - (double, time, time)) - -typedef PointXYZIRPYT PointTypePose; - - -class mapOptimization : public ParamServer -{ - -public: - - // gtsam - NonlinearFactorGraph gtSAMgraph; // Our factor graph https://gtsam.org/tutorials/intro.html#magicparlabel-65411 - Values initialEstimate; - Values optimizedEstimate; - ISAM2 *isam; - Values isamCurrentEstimate; - Eigen::MatrixXd poseCovariance; - - rclcpp::Publisher::SharedPtr pubLaserCloudSurround; - rclcpp::Publisher::SharedPtr pubLaserOdometryGlobal; - rclcpp::Publisher::SharedPtr pubLaserOdometryIncremental; - rclcpp::Publisher::SharedPtr pubKeyPoses; - rclcpp::Publisher::SharedPtr pubPath; - - rclcpp::Publisher::SharedPtr pubHistoryKeyFrames; - rclcpp::Publisher::SharedPtr pubIcpKeyFrames; - rclcpp::Publisher::SharedPtr pubRecentKeyFrames; - rclcpp::Publisher::SharedPtr pubRecentKeyFrame; - rclcpp::Publisher::SharedPtr pubCloudRegisteredRaw; - rclcpp::Publisher::SharedPtr pubLoopConstraintEdge; - - rclcpp::Subscription::SharedPtr subCloud; // Sub to feature p-clouds from featureExtraction - rclcpp::Subscription::SharedPtr subGPS; // Sub to GPS odom - rclcpp::Subscription::SharedPtr subLoop; - rclcpp::Service::SharedPtr saveMapService; - - std::deque gpsQueue; - float m_gpsHeading; - lio_sam::msg::CloudInfo cloudInfo; - - vector::Ptr> cornerCloudKeyFrames; // Pointcloud for corner features - vector::Ptr> surfCloudKeyFrames; // Pcloud for surface features - - pcl::PointCloud::Ptr cloudKeyPoses3D; - pcl::PointCloud::Ptr cloudKeyPoses6D; - pcl::PointCloud::Ptr copy_cloudKeyPoses3D; - pcl::PointCloud::Ptr copy_cloudKeyPoses6D; - - pcl::PointCloud::Ptr laserCloudCornerLast; // corner feature set from odoOptimization - pcl::PointCloud::Ptr laserCloudSurfLast; // surf feature set from odoOptimization - pcl::PointCloud::Ptr laserCloudCornerLastDS; // downsampled corner featuer set from odoOptimization - pcl::PointCloud::Ptr laserCloudSurfLastDS; // downsampled surf featuer set from odoOptimization - - pcl::PointCloud::Ptr laserCloudOri; - pcl::PointCloud::Ptr coeffSel; - - std::vector laserCloudOriCornerVec; // corner point holder for parallel computation - std::vector coeffSelCornerVec; - std::vector laserCloudOriCornerFlag; - std::vector laserCloudOriSurfVec; // surf point holder for parallel computation - std::vector coeffSelSurfVec; - std::vector laserCloudOriSurfFlag; - - map, pcl::PointCloud>> laserCloudMapContainer; - pcl::PointCloud::Ptr laserCloudCornerFromMap; - pcl::PointCloud::Ptr laserCloudSurfFromMap; - pcl::PointCloud::Ptr laserCloudCornerFromMapDS; - pcl::PointCloud::Ptr laserCloudSurfFromMapDS; - - pcl::KdTreeFLANN::Ptr kdtreeCornerFromMap; - pcl::KdTreeFLANN::Ptr kdtreeSurfFromMap; - - pcl::KdTreeFLANN::Ptr kdtreeSurroundingKeyPoses; - pcl::KdTreeFLANN::Ptr kdtreeHistoryKeyPoses; - - pcl::VoxelGrid downSizeFilterCorner; - pcl::VoxelGrid downSizeFilterSurf; - pcl::VoxelGrid downSizeFilterICP; - pcl::VoxelGrid downSizeFilterSurroundingKeyPoses; // for surrounding key poses of scan-to-map optimization - - rclcpp::Time timeLaserInfoStamp; - double timeLaserInfoCur; - - float transformTobeMapped[6]; - - std::mutex mtx; - std::mutex mtxLoopInfo; - - bool isDegenerate = false; - Eigen::Matrix matP; - - int laserCloudCornerFromMapDSNum = 0; - int laserCloudSurfFromMapDSNum = 0; - int laserCloudCornerLastDSNum = 0; - int laserCloudSurfLastDSNum = 0; - - bool aLoopIsClosed = false; - map loopIndexContainer; // from new to old - vector> loopIndexQueue; - vector loopPoseQueue; - vector loopNoiseQueue; - deque loopInfoVec; - - nav_msgs::msg::Path globalPath; - - Eigen::Affine3f transPointAssociateToMap; - Eigen::Affine3f incrementalOdometryAffineFront; - Eigen::Affine3f incrementalOdometryAffineBack; - - std::unique_ptr br; - - mapOptimization(const rclcpp::NodeOptions & options) : ParamServer("lio_sam_mapOptimization", options) - { - ISAM2Params parameters; - parameters.relinearizeThreshold = 0.1; - parameters.relinearizeSkip = 1; - isam = new ISAM2(parameters); - - pubKeyPoses = create_publisher("lio_sam/mapping/trajectory", 1); - pubLaserCloudSurround = create_publisher("lio_sam/mapping/map_global", 1); - pubLaserOdometryGlobal = create_publisher("lio_sam/mapping/odometry", qos); - pubLaserOdometryIncremental = create_publisher( - "lio_sam/mapping/odometry_incremental", qos); - pubPath = create_publisher("lio_sam/mapping/path", 1); - br = std::make_unique(this); - - subCloud = create_subscription( - "lio_sam/feature/cloud_info", qos, - std::bind(&mapOptimization::laserCloudInfoHandler, this, std::placeholders::_1)); - subGPS = create_subscription( - gpsTopic, 200, - std::bind(&mapOptimization::gpsHandler, this, std::placeholders::_1)); - auto subGPS = create_subscription( - "/gps/heading", 200, - std::bind(&mapOptimization::gpsHeadingCb, this, std::placeholders::_1)); - subLoop = create_subscription( - "lio_loop/loop_closure_detection", qos, - std::bind(&mapOptimization::loopInfoHandler, this, std::placeholders::_1)); - saveMapService = create_service("save_map", std::bind(&mapOptimization::saveMap, this, std::placeholders::_1, std::placeholders::_2)); - - - pubHistoryKeyFrames = create_publisher("lio_sam/mapping/icp_loop_closure_history_cloud", 1); - pubIcpKeyFrames = create_publisher("lio_sam/mapping/icp_loop_closure_history_cloud", 1); - pubLoopConstraintEdge = create_publisher("/lio_sam/mapping/loop_closure_constraints", 1); - - pubRecentKeyFrames = create_publisher("lio_sam/mapping/map_local", 1); - pubRecentKeyFrame = create_publisher("lio_sam/mapping/cloud_registered", 1); - pubCloudRegisteredRaw = create_publisher("lio_sam/mapping/cloud_registered_raw", 1); - - downSizeFilterCorner.setLeafSize(mappingCornerLeafSize, mappingCornerLeafSize, mappingCornerLeafSize); - downSizeFilterSurf.setLeafSize(mappingSurfLeafSize, mappingSurfLeafSize, mappingSurfLeafSize); - downSizeFilterICP.setLeafSize(mappingSurfLeafSize, mappingSurfLeafSize, mappingSurfLeafSize); - downSizeFilterSurroundingKeyPoses.setLeafSize(surroundingKeyframeDensity, surroundingKeyframeDensity, surroundingKeyframeDensity); // for surrounding key poses of scan-to-map optimization - - allocateMemory(); - } - - void allocateMemory() - { - cloudKeyPoses3D.reset(new pcl::PointCloud()); - cloudKeyPoses6D.reset(new pcl::PointCloud()); - copy_cloudKeyPoses3D.reset(new pcl::PointCloud()); - copy_cloudKeyPoses6D.reset(new pcl::PointCloud()); - - kdtreeSurroundingKeyPoses.reset(new pcl::KdTreeFLANN()); - kdtreeHistoryKeyPoses.reset(new pcl::KdTreeFLANN()); - - laserCloudCornerLast.reset(new pcl::PointCloud()); // corner feature set from odoOptimization - laserCloudSurfLast.reset(new pcl::PointCloud()); // surf feature set from odoOptimization - laserCloudCornerLastDS.reset(new pcl::PointCloud()); // downsampled corner featuer set from odoOptimization - laserCloudSurfLastDS.reset(new pcl::PointCloud()); // downsampled surf featuer set from odoOptimization - - laserCloudOri.reset(new pcl::PointCloud()); - coeffSel.reset(new pcl::PointCloud()); - - laserCloudOriCornerVec.resize(N_SCAN * Horizon_SCAN); - coeffSelCornerVec.resize(N_SCAN * Horizon_SCAN); - laserCloudOriCornerFlag.resize(N_SCAN * Horizon_SCAN); - laserCloudOriSurfVec.resize(N_SCAN * Horizon_SCAN); - coeffSelSurfVec.resize(N_SCAN * Horizon_SCAN); - laserCloudOriSurfFlag.resize(N_SCAN * Horizon_SCAN); - - std::fill(laserCloudOriCornerFlag.begin(), laserCloudOriCornerFlag.end(), false); - std::fill(laserCloudOriSurfFlag.begin(), laserCloudOriSurfFlag.end(), false); - - laserCloudCornerFromMap.reset(new pcl::PointCloud()); - laserCloudSurfFromMap.reset(new pcl::PointCloud()); - laserCloudCornerFromMapDS.reset(new pcl::PointCloud()); - laserCloudSurfFromMapDS.reset(new pcl::PointCloud()); - - kdtreeCornerFromMap.reset(new pcl::KdTreeFLANN()); - kdtreeSurfFromMap.reset(new pcl::KdTreeFLANN()); - - for (int i = 0; i < 6; ++i){ - transformTobeMapped[i] = 0; - } - - matP.setZero(); - } - - void laserCloudInfoHandler(const lio_sam::msg::CloudInfo::SharedPtr msgIn) - { - // extract time stamp - timeLaserInfoStamp = msgIn->header.stamp; - timeLaserInfoCur = stamp2Sec(msgIn->header.stamp); - - // extract info and feature cloud - cloudInfo = *msgIn; - pcl::fromROSMsg(msgIn->cloud_corner, *laserCloudCornerLast); - pcl::fromROSMsg(msgIn->cloud_surface, *laserCloudSurfLast); - - std::lock_guard lock(mtx); - - static double timeLastProcessing = -1; - if (timeLaserInfoCur - timeLastProcessing >= mappingProcessInterval) - { - timeLastProcessing = timeLaserInfoCur; - - updateInitialGuess(); - - extractSurroundingKeyFrames(); - - downsampleCurrentScan(); - - scan2MapOptimization(); - - saveKeyFramesAndFactor(); - - correctPoses(); - - publishOdometry(); - - publishFrames(); - } - } - - void gpsHandler(const nav_msgs::msg::Odometry::SharedPtr gpsMsg) - { - // RCLCPP_INFO(get_logger(), "Adding GPS to queue"); - gpsQueue.push_back(*gpsMsg); - } - - void gpsHeadingCb(const std_msgs::msg::Float32::SharedPtr gpsHeading) { - m_gpsHeading = gpsHeading->data; - } - - // What is this? point_in, point_out = PointXYZI - void pointAssociateToMap(PointType const * const point_in, PointType * const point_out) - { - point_out->x = transPointAssociateToMap(0,0) * point_in->x + transPointAssociateToMap(0,1) * point_in->y + transPointAssociateToMap(0,2) * point_in->z + transPointAssociateToMap(0,3); - point_out->y = transPointAssociateToMap(1,0) * point_in->x + transPointAssociateToMap(1,1) * point_in->y + transPointAssociateToMap(1,2) * point_in->z + transPointAssociateToMap(1,3); - point_out->z = transPointAssociateToMap(2,0) * point_in->x + transPointAssociateToMap(2,1) * point_in->y + transPointAssociateToMap(2,2) * point_in->z + transPointAssociateToMap(2,3); - point_out->intensity = point_in->intensity; - } - - // Create transformed version of input cloud using provided tf, as expected - pcl::PointCloud::Ptr transformPointCloud(pcl::PointCloud::Ptr cloudIn, PointTypePose* transformIn) - { - pcl::PointCloud::Ptr cloudOut(new pcl::PointCloud()); - - int cloudSize = cloudIn->size(); - cloudOut->resize(cloudSize); - - // Convert transformIn: pointXYZIRT to Eigen::Affine3f - Eigen::Affine3f transCur = pcl::getTransformation(transformIn->x, transformIn->y, transformIn->z, transformIn->roll, transformIn->pitch, transformIn->yaw); - - // Transform each point in cloud, assign to cloudOut - #pragma omp parallel for num_threads(numberOfCores) //Optimization - for (int i = 0; i < cloudSize; ++i) - { - const auto &pointFrom = cloudIn->points[i]; - cloudOut->points[i].x = transCur(0,0) * pointFrom.x + transCur(0,1) * pointFrom.y + transCur(0,2) * pointFrom.z + transCur(0,3); - cloudOut->points[i].y = transCur(1,0) * pointFrom.x + transCur(1,1) * pointFrom.y + transCur(1,2) * pointFrom.z + transCur(1,3); - cloudOut->points[i].z = transCur(2,0) * pointFrom.x + transCur(2,1) * pointFrom.y + transCur(2,2) * pointFrom.z + transCur(2,3); - cloudOut->points[i].intensity = pointFrom.intensity; - } - return cloudOut; - } - - gtsam::Pose3 pclPointTogtsamPose3(PointTypePose thisPoint) - { - return gtsam::Pose3(gtsam::Rot3::RzRyRx(double(thisPoint.roll), double(thisPoint.pitch), double(thisPoint.yaw)), - gtsam::Point3(double(thisPoint.x), double(thisPoint.y), double(thisPoint.z))); - } - - gtsam::Pose3 trans2gtsamPose(float transformIn[]) - { - return gtsam::Pose3(gtsam::Rot3::RzRyRx(transformIn[0], transformIn[1], transformIn[2]), - gtsam::Point3(transformIn[3], transformIn[4], transformIn[5])); - } - - Eigen::Affine3f pclPointToAffine3f(PointTypePose thisPoint) - { - return pcl::getTransformation(thisPoint.x, thisPoint.y, thisPoint.z, thisPoint.roll, thisPoint.pitch, thisPoint.yaw); - } - - Eigen::Affine3f trans2Affine3f(float transformIn[]) - { - return pcl::getTransformation(transformIn[3], transformIn[4], transformIn[5], transformIn[0], transformIn[1], transformIn[2]); - } - - PointTypePose trans2PointTypePose(float transformIn[]) - { - PointTypePose thisPose6D; - thisPose6D.x = transformIn[3]; - thisPose6D.y = transformIn[4]; - thisPose6D.z = transformIn[5]; - thisPose6D.roll = transformIn[0]; - thisPose6D.pitch = transformIn[1]; - thisPose6D.yaw = transformIn[2]; - return thisPose6D; - } - - void saveMap(const std::shared_ptr request, - std::shared_ptr response) { - cout << "****************************************************" << endl; - cout << "Saving map to pcd files ..." << endl; - int timestamp = this->get_clock()->now().seconds(); - savePCDDirectory = std::getenv("HOME") + savePCDDirectory + std::to_string(timestamp) + "/"; - int unused = system((std::string("exec rm -r ") + savePCDDirectory).c_str()); // Clear existing directory - unused = system((std::string("mkdir ") + savePCDDirectory).c_str()); // Create new directory - pcl::io::savePCDFileASCII(savePCDDirectory + "trajectory.pcd", *cloudKeyPoses3D); - pcl::io::savePCDFileASCII(savePCDDirectory + "transformations.pcd", *cloudKeyPoses6D); - pcl::PointCloud::Ptr globalCornerCloud(new pcl::PointCloud()); - pcl::PointCloud::Ptr globalCornerCloudDS(new pcl::PointCloud()); - pcl::PointCloud::Ptr globalSurfCloud(new pcl::PointCloud()); - pcl::PointCloud::Ptr globalSurfCloudDS(new pcl::PointCloud()); - pcl::PointCloud::Ptr globalMapCloud(new pcl::PointCloud()); - for (int i = 0; i < (int)cloudKeyPoses3D->size(); i++) { - *globalCornerCloud += *transformPointCloud(cornerCloudKeyFrames[i], &cloudKeyPoses6D->points[i]); - *globalSurfCloud += *transformPointCloud(surfCloudKeyFrames[i], &cloudKeyPoses6D->points[i]); - cout << "\r" << std::flush << "Processing feature cloud " << i << " of " << cloudKeyPoses6D->size() << " ..."; - } - downSizeFilterCorner.setInputCloud(globalCornerCloud); - downSizeFilterCorner.filter(*globalCornerCloudDS); - pcl::io::savePCDFileASCII(savePCDDirectory + "/cloudCorner.pcd", *globalCornerCloudDS); - downSizeFilterSurf.setInputCloud(globalSurfCloud); - downSizeFilterSurf.filter(*globalSurfCloudDS); - pcl::io::savePCDFileASCII(savePCDDirectory + "/cloudSurf.pcd", *globalSurfCloudDS); - *globalMapCloud += *globalCornerCloud; - *globalMapCloud += *globalSurfCloud; - pcl::io::savePCDFileASCII(savePCDDirectory + "/cloudGlobal.pcd", *globalMapCloud); - cout << "****************************************************" << endl; - cout << "Saving map to pcd files completed" << endl; - response->success = true; - response->message = "Successfully saved map to "+savePCDDirectory; - } - - void visualizeGlobalMapThread() - { - rclcpp::Rate rate(0.2); - while (rclcpp::ok()){ - rate.sleep(); - publishGlobalMap(); - } - if (savePCD == false) - return; - // cout << "****************************************************" << endl; - // cout << "Saving map to pcd files ..." << endl; - // savePCDDirectory = std::getenv("HOME") + savePCDDirectory; - // int unused = system((std::string("exec rm -r ") + savePCDDirectory).c_str()); - // unused = system((std::string("mkdir ") + savePCDDirectory).c_str()); - // pcl::io::savePCDFileASCII(savePCDDirectory + "trajectory.pcd", *cloudKeyPoses3D); - // pcl::io::savePCDFileASCII(savePCDDirectory + "transformations.pcd", *cloudKeyPoses6D); - // pcl::PointCloud::Ptr globalCornerCloud(new pcl::PointCloud()); - // pcl::PointCloud::Ptr globalCornerCloudDS(new pcl::PointCloud()); - // pcl::PointCloud::Ptr globalSurfCloud(new pcl::PointCloud()); - // pcl::PointCloud::Ptr globalSurfCloudDS(new pcl::PointCloud()); - // pcl::PointCloud::Ptr globalMapCloud(new pcl::PointCloud()); - // for (int i = 0; i < (int)cloudKeyPoses3D->size(); i++) { - // *globalCornerCloud += *transformPointCloud(cornerCloudKeyFrames[i], &cloudKeyPoses6D->points[i]); - // *globalSurfCloud += *transformPointCloud(surfCloudKeyFrames[i], &cloudKeyPoses6D->points[i]); - // cout << "\r" << std::flush << "Processing feature cloud " << i << " of " << cloudKeyPoses6D->size() << " ..."; - // } - // downSizeFilterCorner.setInputCloud(globalCornerCloud); - // downSizeFilterCorner.filter(*globalCornerCloudDS); - // std::string rand_id = std::to_string(rand()); - // pcl::io::savePCDFileASCII(savePCDDirectory + "cloudCorner.pcd"+rand_id, *globalCornerCloudDS); - // downSizeFilterSurf.setInputCloud(globalSurfCloud); - // downSizeFilterSurf.filter(*globalSurfCloudDS); - // pcl::io::savePCDFileASCII(savePCDDirectory + "cloudSurf.pcd"+rand_id, *globalSurfCloudDS); - // *globalMapCloud += *globalCornerCloud; - // *globalMapCloud += *globalSurfCloud; - // pcl::io::savePCDFileASCII(savePCDDirectory + "cloudGlobal.pcd"+rand_id, *globalMapCloud); - // cout << "****************************************************" << endl; - // cout << "Saving map to pcd files completed" << endl; - } - - void publishGlobalMap() - { - if (pubLaserCloudSurround->get_subscription_count() == 0) // Optimization - return; - - if (cloudKeyPoses3D->points.empty() == true) - return; - - pcl::KdTreeFLANN::Ptr kdtreeGlobalMap(new pcl::KdTreeFLANN());; - pcl::PointCloud::Ptr globalMapKeyPoses(new pcl::PointCloud()); - pcl::PointCloud::Ptr globalMapKeyPosesDS(new pcl::PointCloud()); - pcl::PointCloud::Ptr globalMapKeyFrames(new pcl::PointCloud()); - pcl::PointCloud::Ptr globalMapKeyFramesDS(new pcl::PointCloud()); - - // kd-tree to find near key frames to visualize - std::vector pointSearchIndGlobalMap; //Indices map for kd tree - std::vector pointSearchSqDisGlobalMap; // Square distance - // search near key frames to visualize - mtx.lock(); - kdtreeGlobalMap->setInputCloud(cloudKeyPoses3D); - kdtreeGlobalMap->radiusSearch(cloudKeyPoses3D->back(), globalMapVisualizationSearchRadius, pointSearchIndGlobalMap, pointSearchSqDisGlobalMap, 0); - mtx.unlock(); - - for (int i = 0; i < (int)pointSearchIndGlobalMap.size(); ++i) - globalMapKeyPoses->push_back(cloudKeyPoses3D->points[pointSearchIndGlobalMap[i]]); - // downsample near selected key frames - pcl::VoxelGrid downSizeFilterGlobalMapKeyPoses; // for global map visualization - downSizeFilterGlobalMapKeyPoses.setLeafSize(globalMapVisualizationPoseDensity, globalMapVisualizationPoseDensity, globalMapVisualizationPoseDensity); // for global map visualization - downSizeFilterGlobalMapKeyPoses.setInputCloud(globalMapKeyPoses); - downSizeFilterGlobalMapKeyPoses.filter(*globalMapKeyPosesDS); - for(auto& pt : globalMapKeyPosesDS->points) - { - kdtreeGlobalMap->nearestKSearch(pt, 1, pointSearchIndGlobalMap, pointSearchSqDisGlobalMap); - pt.intensity = cloudKeyPoses3D->points[pointSearchIndGlobalMap[0]].intensity; - } - - // extract visualized and downsampled key frames - for (int i = 0; i < (int)globalMapKeyPosesDS->size(); ++i){ - if (pointDistance(globalMapKeyPosesDS->points[i], cloudKeyPoses3D->back()) > globalMapVisualizationSearchRadius) - continue; - int thisKeyInd = (int)globalMapKeyPosesDS->points[i].intensity; - *globalMapKeyFrames += *transformPointCloud(cornerCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]); - *globalMapKeyFrames += *transformPointCloud(surfCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]); - } - // downsample visualized points - pcl::VoxelGrid downSizeFilterGlobalMapKeyFrames; // for global map visualization - downSizeFilterGlobalMapKeyFrames.setLeafSize(globalMapVisualizationLeafSize, globalMapVisualizationLeafSize, globalMapVisualizationLeafSize); // for global map visualization - downSizeFilterGlobalMapKeyFrames.setInputCloud(globalMapKeyFrames); - downSizeFilterGlobalMapKeyFrames.filter(*globalMapKeyFramesDS); - RCLCPP_INFO(get_logger(), "Publishing global map"); - publishCloud(pubLaserCloudSurround, globalMapKeyFramesDS, timeLaserInfoStamp, odometryFrame); - } - - - - - - - - - - - - - void loopClosureThread() - { - if (loopClosureEnableFlag == false) - return; - - rclcpp::Rate rate(loopClosureFrequency); - while (rclcpp::ok()) - { - rate.sleep(); - performLoopClosure(); - visualizeLoopClosure(); - } - } - - void loopInfoHandler(const std_msgs::msg::Float64MultiArray::SharedPtr loopMsg) - { - std::lock_guard lock(mtxLoopInfo); - if (loopMsg->data.size() != 2) - return; - - loopInfoVec.push_back(*loopMsg); - - while (loopInfoVec.size() > 5) - loopInfoVec.pop_front(); - } - - void performLoopClosure() - { - if (cloudKeyPoses3D->points.empty() == true) - return; - - mtx.lock(); - *copy_cloudKeyPoses3D = *cloudKeyPoses3D; - *copy_cloudKeyPoses6D = *cloudKeyPoses6D; - mtx.unlock(); - - // find keys - int loopKeyCur; - int loopKeyPre; - if (detectLoopClosureExternal(&loopKeyCur, &loopKeyPre) == false) - if (detectLoopClosureDistance(&loopKeyCur, &loopKeyPre) == false) - return; - - // extract cloud - pcl::PointCloud::Ptr cureKeyframeCloud(new pcl::PointCloud()); - pcl::PointCloud::Ptr prevKeyframeCloud(new pcl::PointCloud()); - { - loopFindNearKeyframes(cureKeyframeCloud, loopKeyCur, 0); - loopFindNearKeyframes(prevKeyframeCloud, loopKeyPre, historyKeyframeSearchNum); - if (cureKeyframeCloud->size() < 300 || prevKeyframeCloud->size() < 1000) - return; - if (pubHistoryKeyFrames->get_subscription_count() != 0) - publishCloud(pubHistoryKeyFrames, prevKeyframeCloud, timeLaserInfoStamp, odometryFrame); - } - - // ICP Settings - static pcl::IterativeClosestPoint icp; - icp.setMaxCorrespondenceDistance(historyKeyframeSearchRadius*2); - icp.setMaximumIterations(100); - icp.setTransformationEpsilon(1e-6); - icp.setEuclideanFitnessEpsilon(1e-6); - icp.setRANSACIterations(0); - - // Align clouds - icp.setInputSource(cureKeyframeCloud); - icp.setInputTarget(prevKeyframeCloud); - pcl::PointCloud::Ptr unused_result(new pcl::PointCloud()); - icp.align(*unused_result); - - if (icp.hasConverged() == false || icp.getFitnessScore() > historyKeyframeFitnessScore) - return; - - // publish corrected cloud - if (pubIcpKeyFrames->get_subscription_count() != 0) - { - pcl::PointCloud::Ptr closed_cloud(new pcl::PointCloud()); - pcl::transformPointCloud(*cureKeyframeCloud, *closed_cloud, icp.getFinalTransformation()); - publishCloud(pubIcpKeyFrames, closed_cloud, timeLaserInfoStamp, odometryFrame); - } - - // Get pose transformation - float x, y, z, roll, pitch, yaw; - Eigen::Affine3f correctionLidarFrame; - correctionLidarFrame = icp.getFinalTransformation(); - // transform from world origin to wrong pose - Eigen::Affine3f tWrong = pclPointToAffine3f(copy_cloudKeyPoses6D->points[loopKeyCur]); - // transform from world origin to corrected pose - Eigen::Affine3f tCorrect = correctionLidarFrame * tWrong;// pre-multiplying -> successive rotation about a fixed frame - pcl::getTranslationAndEulerAngles (tCorrect, x, y, z, roll, pitch, yaw); - gtsam::Pose3 poseFrom = Pose3(Rot3::RzRyRx(roll, pitch, yaw), Point3(x, y, z)); - gtsam::Pose3 poseTo = pclPointTogtsamPose3(copy_cloudKeyPoses6D->points[loopKeyPre]); - gtsam::Vector Vector6(6); - float noiseScore = icp.getFitnessScore(); - Vector6 << noiseScore, noiseScore, noiseScore, noiseScore, noiseScore, noiseScore; - noiseModel::Diagonal::shared_ptr constraintNoise = noiseModel::Diagonal::Variances(Vector6); - - // Add pose constraint - mtx.lock(); - loopIndexQueue.push_back(make_pair(loopKeyCur, loopKeyPre)); - loopPoseQueue.push_back(poseFrom.between(poseTo)); - loopNoiseQueue.push_back(constraintNoise); - mtx.unlock(); - - // add loop constriant - loopIndexContainer[loopKeyCur] = loopKeyPre; - } - - bool detectLoopClosureDistance(int *latestID, int *closestID) - { - int loopKeyCur = copy_cloudKeyPoses3D->size() - 1; - int loopKeyPre = -1; - - // check loop constraint added before - auto it = loopIndexContainer.find(loopKeyCur); - if (it != loopIndexContainer.end()) - return false; - - // find the closest history key frame - std::vector pointSearchIndLoop; - std::vector pointSearchSqDisLoop; - kdtreeHistoryKeyPoses->setInputCloud(copy_cloudKeyPoses3D); - kdtreeHistoryKeyPoses->radiusSearch(copy_cloudKeyPoses3D->back(), historyKeyframeSearchRadius, pointSearchIndLoop, pointSearchSqDisLoop, 0); - - for (int i = 0; i < (int)pointSearchIndLoop.size(); ++i) - { - int id = pointSearchIndLoop[i]; - if (abs(copy_cloudKeyPoses6D->points[id].time - timeLaserInfoCur) > historyKeyframeSearchTimeDiff) - { - loopKeyPre = id; - break; - } - } - - if (loopKeyPre == -1 || loopKeyCur == loopKeyPre) - return false; - - *latestID = loopKeyCur; - *closestID = loopKeyPre; - - return true; - } - - bool detectLoopClosureExternal(int *latestID, int *closestID) - { - // this function is not used yet, please ignore it - int loopKeyCur = -1; - int loopKeyPre = -1; - - std::lock_guard lock(mtxLoopInfo); - if (loopInfoVec.empty()) - return false; - - double loopTimeCur = loopInfoVec.front().data[0]; - double loopTimePre = loopInfoVec.front().data[1]; - loopInfoVec.pop_front(); - - if (abs(loopTimeCur - loopTimePre) < historyKeyframeSearchTimeDiff) - return false; - - int cloudSize = copy_cloudKeyPoses6D->size(); - if (cloudSize < 2) - return false; - - // latest key - loopKeyCur = cloudSize - 1; - for (int i = cloudSize - 1; i >= 0; --i) - { - if (copy_cloudKeyPoses6D->points[i].time >= loopTimeCur) - loopKeyCur = round(copy_cloudKeyPoses6D->points[i].intensity); - else - break; - } - - // previous key - loopKeyPre = 0; - for (int i = 0; i < cloudSize; ++i) - { - if (copy_cloudKeyPoses6D->points[i].time <= loopTimePre) - loopKeyPre = round(copy_cloudKeyPoses6D->points[i].intensity); - else - break; - } - - if (loopKeyCur == loopKeyPre) - return false; - - auto it = loopIndexContainer.find(loopKeyCur); - if (it != loopIndexContainer.end()) - return false; - - *latestID = loopKeyCur; - *closestID = loopKeyPre; - - return true; - } - - void loopFindNearKeyframes(pcl::PointCloud::Ptr& nearKeyframes, const int& key, const int& searchNum) - { - // extract near keyframes - nearKeyframes->clear(); - int cloudSize = copy_cloudKeyPoses6D->size(); - for (int i = -searchNum; i <= searchNum; ++i) - { - int keyNear = key + i; - if (keyNear < 0 || keyNear >= cloudSize ) - continue; - *nearKeyframes += *transformPointCloud(cornerCloudKeyFrames[keyNear], ©_cloudKeyPoses6D->points[keyNear]); - *nearKeyframes += *transformPointCloud(surfCloudKeyFrames[keyNear], ©_cloudKeyPoses6D->points[keyNear]); - } - - if (nearKeyframes->empty()) - return; - - // downsample near keyframes - pcl::PointCloud::Ptr cloud_temp(new pcl::PointCloud()); - downSizeFilterICP.setInputCloud(nearKeyframes); - downSizeFilterICP.filter(*cloud_temp); - *nearKeyframes = *cloud_temp; - } - - void visualizeLoopClosure() - { - if (loopIndexContainer.empty()) - return; - - visualization_msgs::msg::MarkerArray markerArray; - // loop nodes - visualization_msgs::msg::Marker markerNode; - markerNode.header.frame_id = odometryFrame; - markerNode.header.stamp = timeLaserInfoStamp; - markerNode.action = visualization_msgs::msg::Marker::ADD; - markerNode.type = visualization_msgs::msg::Marker::SPHERE_LIST; - markerNode.ns = "loop_nodes"; - markerNode.id = 0; - markerNode.pose.orientation.w = 1; - markerNode.scale.x = 0.3; markerNode.scale.y = 0.3; markerNode.scale.z = 0.3; - markerNode.color.r = 0; markerNode.color.g = 0.8; markerNode.color.b = 1; - markerNode.color.a = 1; - // loop edges - visualization_msgs::msg::Marker markerEdge; - markerEdge.header.frame_id = odometryFrame; - markerEdge.header.stamp = timeLaserInfoStamp; - markerEdge.action = visualization_msgs::msg::Marker::ADD; - markerEdge.type = visualization_msgs::msg::Marker::LINE_LIST; - markerEdge.ns = "loop_edges"; - markerEdge.id = 1; - markerEdge.pose.orientation.w = 1; - markerEdge.scale.x = 0.1; - markerEdge.color.r = 0.9; markerEdge.color.g = 0.9; markerEdge.color.b = 0; - markerEdge.color.a = 1; - - for (auto it = loopIndexContainer.begin(); it != loopIndexContainer.end(); ++it) - { - int key_cur = it->first; - int key_pre = it->second; - geometry_msgs::msg::Point p; - p.x = copy_cloudKeyPoses6D->points[key_cur].x; - p.y = copy_cloudKeyPoses6D->points[key_cur].y; - p.z = copy_cloudKeyPoses6D->points[key_cur].z; - markerNode.points.push_back(p); - markerEdge.points.push_back(p); - p.x = copy_cloudKeyPoses6D->points[key_pre].x; - p.y = copy_cloudKeyPoses6D->points[key_pre].y; - p.z = copy_cloudKeyPoses6D->points[key_pre].z; - markerNode.points.push_back(p); - markerEdge.points.push_back(p); - } - - markerArray.markers.push_back(markerNode); - markerArray.markers.push_back(markerEdge); - pubLoopConstraintEdge->publish(markerArray); - } - - - - - - - - - - - - void updateInitialGuess() - { - // save current transformation before any processing - incrementalOdometryAffineFront = trans2Affine3f(transformTobeMapped); - - static Eigen::Affine3f lastImuTransformation; - // initialization - if (cloudKeyPoses3D->points.empty()) - { - transformTobeMapped[0] = cloudInfo.imu_roll_init; - transformTobeMapped[1] = cloudInfo.imu_pitch_init; - transformTobeMapped[2] = cloudInfo.imu_yaw_init; - - if (!useImuHeadingInitialization) - transformTobeMapped[2] = 0; - - lastImuTransformation = pcl::getTransformation(0, 0, 0, cloudInfo.imu_roll_init, cloudInfo.imu_pitch_init, cloudInfo.imu_yaw_init); // save imu before return; - return; - } - - // use imu pre-integration estimation for pose guess - static bool lastImuPreTransAvailable = false; - static Eigen::Affine3f lastImuPreTransformation; - if (cloudInfo.odom_available == true) - { - Eigen::Affine3f transBack = pcl::getTransformation( - cloudInfo.initial_guess_x, cloudInfo.initial_guess_y, cloudInfo.initial_guess_z, - cloudInfo.initial_guess_roll, cloudInfo.initial_guess_pitch, cloudInfo.initial_guess_yaw); - if (lastImuPreTransAvailable == false) - { - lastImuPreTransformation = transBack; - lastImuPreTransAvailable = true; - } else { - Eigen::Affine3f transIncre = lastImuPreTransformation.inverse() * transBack; - Eigen::Affine3f transTobe = trans2Affine3f(transformTobeMapped); - Eigen::Affine3f transFinal = transTobe * transIncre; - pcl::getTranslationAndEulerAngles(transFinal, transformTobeMapped[3], transformTobeMapped[4], transformTobeMapped[5], - transformTobeMapped[0], transformTobeMapped[1], transformTobeMapped[2]); - - lastImuPreTransformation = transBack; - - lastImuTransformation = pcl::getTransformation(0, 0, 0, cloudInfo.imu_roll_init, cloudInfo.imu_pitch_init, cloudInfo.imu_yaw_init); // save imu before return; - return; - } - } - - // use imu incremental estimation for pose guess (only rotation) - if (cloudInfo.imu_available == true) - { - Eigen::Affine3f transBack = pcl::getTransformation(0, 0, 0, cloudInfo.imu_roll_init, cloudInfo.imu_pitch_init, cloudInfo.imu_yaw_init); - Eigen::Affine3f transIncre = lastImuTransformation.inverse() * transBack; - - Eigen::Affine3f transTobe = trans2Affine3f(transformTobeMapped); - Eigen::Affine3f transFinal = transTobe * transIncre; - pcl::getTranslationAndEulerAngles(transFinal, transformTobeMapped[3], transformTobeMapped[4], transformTobeMapped[5], - transformTobeMapped[0], transformTobeMapped[1], transformTobeMapped[2]); - - lastImuTransformation = pcl::getTransformation(0, 0, 0, cloudInfo.imu_roll_init, cloudInfo.imu_pitch_init, cloudInfo.imu_yaw_init); // save imu before return; - return; - } - } - - void extractForLoopClosure() - { - pcl::PointCloud::Ptr cloudToExtract(new pcl::PointCloud()); - int numPoses = cloudKeyPoses3D->size(); - for (int i = numPoses-1; i >= 0; --i) - { - if ((int)cloudToExtract->size() <= surroundingKeyframeSize) - cloudToExtract->push_back(cloudKeyPoses3D->points[i]); - else - break; - } - - extractCloud(cloudToExtract); - } - - void extractNearby() - { - pcl::PointCloud::Ptr surroundingKeyPoses(new pcl::PointCloud()); - pcl::PointCloud::Ptr surroundingKeyPosesDS(new pcl::PointCloud()); - std::vector pointSearchInd; - std::vector pointSearchSqDis; - - // extract all the nearby key poses and downsample them - kdtreeSurroundingKeyPoses->setInputCloud(cloudKeyPoses3D); // create kd-tree - kdtreeSurroundingKeyPoses->radiusSearch(cloudKeyPoses3D->back(), (double)surroundingKeyframeSearchRadius, pointSearchInd, pointSearchSqDis); - for (int i = 0; i < (int)pointSearchInd.size(); ++i) - { - int id = pointSearchInd[i]; - surroundingKeyPoses->push_back(cloudKeyPoses3D->points[id]); - } - - downSizeFilterSurroundingKeyPoses.setInputCloud(surroundingKeyPoses); - downSizeFilterSurroundingKeyPoses.filter(*surroundingKeyPosesDS); - for(auto& pt : surroundingKeyPosesDS->points) - { - kdtreeSurroundingKeyPoses->nearestKSearch(pt, 1, pointSearchInd, pointSearchSqDis); - pt.intensity = cloudKeyPoses3D->points[pointSearchInd[0]].intensity; - } - - // also extract some latest key frames in case the robot rotates in one position - int numPoses = cloudKeyPoses3D->size(); - for (int i = numPoses-1; i >= 0; --i) - { - if (timeLaserInfoCur - cloudKeyPoses6D->points[i].time < 10.0) - surroundingKeyPosesDS->push_back(cloudKeyPoses3D->points[i]); - else - break; - } - - extractCloud(surroundingKeyPosesDS); - } - - void extractCloud(pcl::PointCloud::Ptr cloudToExtract) - { - // fuse the map - laserCloudCornerFromMap->clear(); - laserCloudSurfFromMap->clear(); - for (int i = 0; i < (int)cloudToExtract->size(); ++i) - { - if (pointDistance(cloudToExtract->points[i], cloudKeyPoses3D->back()) > surroundingKeyframeSearchRadius) - continue; - - int thisKeyInd = (int)cloudToExtract->points[i].intensity; - if (laserCloudMapContainer.find(thisKeyInd) != laserCloudMapContainer.end()) - { - // transformed cloud available - *laserCloudCornerFromMap += laserCloudMapContainer[thisKeyInd].first; - *laserCloudSurfFromMap += laserCloudMapContainer[thisKeyInd].second; - } else { - // transformed cloud not available - pcl::PointCloud laserCloudCornerTemp = *transformPointCloud(cornerCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]); - pcl::PointCloud laserCloudSurfTemp = *transformPointCloud(surfCloudKeyFrames[thisKeyInd], &cloudKeyPoses6D->points[thisKeyInd]); - *laserCloudCornerFromMap += laserCloudCornerTemp; - *laserCloudSurfFromMap += laserCloudSurfTemp; - laserCloudMapContainer[thisKeyInd] = make_pair(laserCloudCornerTemp, laserCloudSurfTemp); - } - - } - - // Downsample the surrounding corner key frames (or map) - downSizeFilterCorner.setInputCloud(laserCloudCornerFromMap); - downSizeFilterCorner.filter(*laserCloudCornerFromMapDS); - laserCloudCornerFromMapDSNum = laserCloudCornerFromMapDS->size(); - // Downsample the surrounding surf key frames (or map) - downSizeFilterSurf.setInputCloud(laserCloudSurfFromMap); - downSizeFilterSurf.filter(*laserCloudSurfFromMapDS); - laserCloudSurfFromMapDSNum = laserCloudSurfFromMapDS->size(); - - // clear map cache if too large - if (laserCloudMapContainer.size() > 1000) - laserCloudMapContainer.clear(); - } - - void extractSurroundingKeyFrames() - { - if (cloudKeyPoses3D->points.empty() == true) - return; - - // if (loopClosureEnableFlag == true) - // { - // extractForLoopClosure(); - // } else { - // extractNearby(); - // } - - extractNearby(); - } - - void downsampleCurrentScan() - { - // Downsample cloud from current scan - laserCloudCornerLastDS->clear(); - downSizeFilterCorner.setInputCloud(laserCloudCornerLast); - downSizeFilterCorner.filter(*laserCloudCornerLastDS); - laserCloudCornerLastDSNum = laserCloudCornerLastDS->size(); - - laserCloudSurfLastDS->clear(); - downSizeFilterSurf.setInputCloud(laserCloudSurfLast); - downSizeFilterSurf.filter(*laserCloudSurfLastDS); - laserCloudSurfLastDSNum = laserCloudSurfLastDS->size(); - } - - void updatePointAssociateToMap() - { - transPointAssociateToMap = trans2Affine3f(transformTobeMapped); - } - - void cornerOptimization() - { - updatePointAssociateToMap(); - - #pragma omp parallel for num_threads(numberOfCores) - for (int i = 0; i < laserCloudCornerLastDSNum; i++) - { - PointType pointOri, pointSel, coeff; - std::vector pointSearchInd; - std::vector pointSearchSqDis; - - pointOri = laserCloudCornerLastDS->points[i]; - pointAssociateToMap(&pointOri, &pointSel); - kdtreeCornerFromMap->nearestKSearch(pointSel, 5, pointSearchInd, pointSearchSqDis); - - cv::Mat matA1(3, 3, CV_32F, cv::Scalar::all(0)); - cv::Mat matD1(1, 3, CV_32F, cv::Scalar::all(0)); - cv::Mat matV1(3, 3, CV_32F, cv::Scalar::all(0)); - - if (pointSearchSqDis[4] < 1.0) { - float cx = 0, cy = 0, cz = 0; - for (int j = 0; j < 5; j++) { - cx += laserCloudCornerFromMapDS->points[pointSearchInd[j]].x; - cy += laserCloudCornerFromMapDS->points[pointSearchInd[j]].y; - cz += laserCloudCornerFromMapDS->points[pointSearchInd[j]].z; - } - cx /= 5; cy /= 5; cz /= 5; - - float a11 = 0, a12 = 0, a13 = 0, a22 = 0, a23 = 0, a33 = 0; - for (int j = 0; j < 5; j++) { - float ax = laserCloudCornerFromMapDS->points[pointSearchInd[j]].x - cx; - float ay = laserCloudCornerFromMapDS->points[pointSearchInd[j]].y - cy; - float az = laserCloudCornerFromMapDS->points[pointSearchInd[j]].z - cz; - - a11 += ax * ax; a12 += ax * ay; a13 += ax * az; - a22 += ay * ay; a23 += ay * az; - a33 += az * az; - } - a11 /= 5; a12 /= 5; a13 /= 5; a22 /= 5; a23 /= 5; a33 /= 5; - - matA1.at(0, 0) = a11; matA1.at(0, 1) = a12; matA1.at(0, 2) = a13; - matA1.at(1, 0) = a12; matA1.at(1, 1) = a22; matA1.at(1, 2) = a23; - matA1.at(2, 0) = a13; matA1.at(2, 1) = a23; matA1.at(2, 2) = a33; - - cv::eigen(matA1, matD1, matV1); - - if (matD1.at(0, 0) > 3 * matD1.at(0, 1)) { - - float x0 = pointSel.x; - float y0 = pointSel.y; - float z0 = pointSel.z; - float x1 = cx + 0.1 * matV1.at(0, 0); - float y1 = cy + 0.1 * matV1.at(0, 1); - float z1 = cz + 0.1 * matV1.at(0, 2); - float x2 = cx - 0.1 * matV1.at(0, 0); - float y2 = cy - 0.1 * matV1.at(0, 1); - float z2 = cz - 0.1 * matV1.at(0, 2); - - float a012 = sqrt(((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) * ((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) - + ((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1)) * ((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1)) - + ((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1)) * ((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1))); - - float l12 = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2)); - - float la = ((y1 - y2)*((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) - + (z1 - z2)*((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1))) / a012 / l12; - - float lb = -((x1 - x2)*((x0 - x1)*(y0 - y2) - (x0 - x2)*(y0 - y1)) - - (z1 - z2)*((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1))) / a012 / l12; - - float lc = -((x1 - x2)*((x0 - x1)*(z0 - z2) - (x0 - x2)*(z0 - z1)) - + (y1 - y2)*((y0 - y1)*(z0 - z2) - (y0 - y2)*(z0 - z1))) / a012 / l12; - - float ld2 = a012 / l12; - - float s = 1 - 0.9 * fabs(ld2); - - coeff.x = s * la; - coeff.y = s * lb; - coeff.z = s * lc; - coeff.intensity = s * ld2; - - if (s > 0.1) { - laserCloudOriCornerVec[i] = pointOri; - coeffSelCornerVec[i] = coeff; - laserCloudOriCornerFlag[i] = true; - } - } - } - } - } - - void surfOptimization() - { - updatePointAssociateToMap(); - - #pragma omp parallel for num_threads(numberOfCores) - for (int i = 0; i < laserCloudSurfLastDSNum; i++) - { - PointType pointOri, pointSel, coeff; - std::vector pointSearchInd; - std::vector pointSearchSqDis; - - pointOri = laserCloudSurfLastDS->points[i]; - pointAssociateToMap(&pointOri, &pointSel); - kdtreeSurfFromMap->nearestKSearch(pointSel, 5, pointSearchInd, pointSearchSqDis); - - Eigen::Matrix matA0; - Eigen::Matrix matB0; - Eigen::Vector3f matX0; - - matA0.setZero(); - matB0.fill(-1); - matX0.setZero(); - - if (pointSearchSqDis[4] < 1.0) { - for (int j = 0; j < 5; j++) { - matA0(j, 0) = laserCloudSurfFromMapDS->points[pointSearchInd[j]].x; - matA0(j, 1) = laserCloudSurfFromMapDS->points[pointSearchInd[j]].y; - matA0(j, 2) = laserCloudSurfFromMapDS->points[pointSearchInd[j]].z; - } - - matX0 = matA0.colPivHouseholderQr().solve(matB0); - - float pa = matX0(0, 0); - float pb = matX0(1, 0); - float pc = matX0(2, 0); - float pd = 1; - - float ps = sqrt(pa * pa + pb * pb + pc * pc); - pa /= ps; pb /= ps; pc /= ps; pd /= ps; - - bool planeValid = true; - for (int j = 0; j < 5; j++) { - if (fabs(pa * laserCloudSurfFromMapDS->points[pointSearchInd[j]].x + - pb * laserCloudSurfFromMapDS->points[pointSearchInd[j]].y + - pc * laserCloudSurfFromMapDS->points[pointSearchInd[j]].z + pd) > 0.2) { - planeValid = false; - break; - } - } - - if (planeValid) { - float pd2 = pa * pointSel.x + pb * pointSel.y + pc * pointSel.z + pd; - - float s = 1 - 0.9 * fabs(pd2) / sqrt(sqrt(pointSel.x * pointSel.x - + pointSel.y * pointSel.y + pointSel.z * pointSel.z)); - - coeff.x = s * pa; - coeff.y = s * pb; - coeff.z = s * pc; - coeff.intensity = s * pd2; - - if (s > 0.1) { - laserCloudOriSurfVec[i] = pointOri; - coeffSelSurfVec[i] = coeff; - laserCloudOriSurfFlag[i] = true; - } - } - } - } - } - - void combineOptimizationCoeffs() - { - // combine corner coeffs - for (int i = 0; i < laserCloudCornerLastDSNum; ++i){ - if (laserCloudOriCornerFlag[i] == true){ - laserCloudOri->push_back(laserCloudOriCornerVec[i]); - coeffSel->push_back(coeffSelCornerVec[i]); - } - } - // combine surf coeffs - for (int i = 0; i < laserCloudSurfLastDSNum; ++i){ - if (laserCloudOriSurfFlag[i] == true){ - laserCloudOri->push_back(laserCloudOriSurfVec[i]); - coeffSel->push_back(coeffSelSurfVec[i]); - } - } - // reset flag for next iteration - std::fill(laserCloudOriCornerFlag.begin(), laserCloudOriCornerFlag.end(), false); - std::fill(laserCloudOriSurfFlag.begin(), laserCloudOriSurfFlag.end(), false); - } - - bool LMOptimization(int iterCount) - { - // This optimization is from the original loam_velodyne by Ji Zhang, need to cope with coordinate transformation - // lidar <- camera --- camera <- lidar - // x = z --- x = y - // y = x --- y = z - // z = y --- z = x - // roll = yaw --- roll = pitch - // pitch = roll --- pitch = yaw - // yaw = pitch --- yaw = roll - - // lidar -> camera - float srx = sin(transformTobeMapped[1]); - float crx = cos(transformTobeMapped[1]); - float sry = sin(transformTobeMapped[2]); - float cry = cos(transformTobeMapped[2]); - float srz = sin(transformTobeMapped[0]); - float crz = cos(transformTobeMapped[0]); - - int laserCloudSelNum = laserCloudOri->size(); - if (laserCloudSelNum < 50) { - return false; - } - - cv::Mat matA(laserCloudSelNum, 6, CV_32F, cv::Scalar::all(0)); - cv::Mat matAt(6, laserCloudSelNum, CV_32F, cv::Scalar::all(0)); - cv::Mat matAtA(6, 6, CV_32F, cv::Scalar::all(0)); - cv::Mat matB(laserCloudSelNum, 1, CV_32F, cv::Scalar::all(0)); - cv::Mat matAtB(6, 1, CV_32F, cv::Scalar::all(0)); - cv::Mat matX(6, 1, CV_32F, cv::Scalar::all(0)); - cv::Mat matP(6, 6, CV_32F, cv::Scalar::all(0)); - - PointType pointOri, coeff; - - for (int i = 0; i < laserCloudSelNum; i++) { - // lidar -> camera - pointOri.x = laserCloudOri->points[i].y; - pointOri.y = laserCloudOri->points[i].z; - pointOri.z = laserCloudOri->points[i].x; - // lidar -> camera - coeff.x = coeffSel->points[i].y; - coeff.y = coeffSel->points[i].z; - coeff.z = coeffSel->points[i].x; - coeff.intensity = coeffSel->points[i].intensity; - // in camera - float arx = (crx*sry*srz*pointOri.x + crx*crz*sry*pointOri.y - srx*sry*pointOri.z) * coeff.x - + (-srx*srz*pointOri.x - crz*srx*pointOri.y - crx*pointOri.z) * coeff.y - + (crx*cry*srz*pointOri.x + crx*cry*crz*pointOri.y - cry*srx*pointOri.z) * coeff.z; - - float ary = ((cry*srx*srz - crz*sry)*pointOri.x - + (sry*srz + cry*crz*srx)*pointOri.y + crx*cry*pointOri.z) * coeff.x - + ((-cry*crz - srx*sry*srz)*pointOri.x - + (cry*srz - crz*srx*sry)*pointOri.y - crx*sry*pointOri.z) * coeff.z; - - float arz = ((crz*srx*sry - cry*srz)*pointOri.x + (-cry*crz-srx*sry*srz)*pointOri.y)*coeff.x - + (crx*crz*pointOri.x - crx*srz*pointOri.y) * coeff.y - + ((sry*srz + cry*crz*srx)*pointOri.x + (crz*sry-cry*srx*srz)*pointOri.y)*coeff.z; - // lidar -> camera - matA.at(i, 0) = arz; - matA.at(i, 1) = arx; - matA.at(i, 2) = ary; - matA.at(i, 3) = coeff.z; - matA.at(i, 4) = coeff.x; - matA.at(i, 5) = coeff.y; - matB.at(i, 0) = -coeff.intensity; - } - - cv::transpose(matA, matAt); - matAtA = matAt * matA; - matAtB = matAt * matB; - cv::solve(matAtA, matAtB, matX, cv::DECOMP_QR); - - if (iterCount == 0) { - - cv::Mat matE(1, 6, CV_32F, cv::Scalar::all(0)); - cv::Mat matV(6, 6, CV_32F, cv::Scalar::all(0)); - cv::Mat matV2(6, 6, CV_32F, cv::Scalar::all(0)); - - cv::eigen(matAtA, matE, matV); - matV.copyTo(matV2); - - isDegenerate = false; - float eignThre[6] = {100, 100, 100, 100, 100, 100}; - for (int i = 5; i >= 0; i--) { - if (matE.at(0, i) < eignThre[i]) { - for (int j = 0; j < 6; j++) { - matV2.at(i, j) = 0; - } - isDegenerate = true; - } else { - break; - } - } - matP = matV.inv() * matV2; - } - - if (isDegenerate) - { - cv::Mat matX2(6, 1, CV_32F, cv::Scalar::all(0)); - matX.copyTo(matX2); - matX = matP * matX2; - } - - transformTobeMapped[0] += matX.at(0, 0); - transformTobeMapped[1] += matX.at(1, 0); - transformTobeMapped[2] += matX.at(2, 0); - transformTobeMapped[3] += matX.at(3, 0); - transformTobeMapped[4] += matX.at(4, 0); - transformTobeMapped[5] += matX.at(5, 0); - - float deltaR = sqrt( - pow(pcl::rad2deg(matX.at(0, 0)), 2) + - pow(pcl::rad2deg(matX.at(1, 0)), 2) + - pow(pcl::rad2deg(matX.at(2, 0)), 2)); - float deltaT = sqrt( - pow(matX.at(3, 0) * 100, 2) + - pow(matX.at(4, 0) * 100, 2) + - pow(matX.at(5, 0) * 100, 2)); - - if (deltaR < 0.05 && deltaT < 0.05) { - return true; // converged - } - return false; // keep optimizing - } - - void scan2MapOptimization() - { - if (cloudKeyPoses3D->points.empty()) - return; - - if (laserCloudCornerLastDSNum > edgeFeatureMinValidNum && laserCloudSurfLastDSNum > surfFeatureMinValidNum) - { - kdtreeCornerFromMap->setInputCloud(laserCloudCornerFromMapDS); - kdtreeSurfFromMap->setInputCloud(laserCloudSurfFromMapDS); - - for (int iterCount = 0; iterCount < 30; iterCount++) - { - laserCloudOri->clear(); - coeffSel->clear(); - - cornerOptimization(); - surfOptimization(); - - combineOptimizationCoeffs(); - - if (LMOptimization(iterCount) == true) - break; - } - - transformUpdate(); - } else { - RCLCPP_WARN(get_logger(), "Not enough features! Only %d edge and %d planar features available.", laserCloudCornerLastDSNum, laserCloudSurfLastDSNum); - } - } - - void transformUpdate() - { - if (cloudInfo.imu_available == true) - { - if (std::abs(cloudInfo.imu_pitch_init) < 1.4) - { - double imuWeight = imuRPYWeight; - tf2::Quaternion imuQuaternion; - tf2::Quaternion transformQuaternion; - double rollMid, pitchMid, yawMid; - - // slerp roll - transformQuaternion.setRPY(transformTobeMapped[0], 0, 0); - imuQuaternion.setRPY(cloudInfo.imu_roll_init, 0, 0); - tf2::Matrix3x3(transformQuaternion.slerp(imuQuaternion, imuWeight)).getRPY(rollMid, pitchMid, yawMid); - transformTobeMapped[0] = rollMid; - - // slerp pitch - transformQuaternion.setRPY(0, transformTobeMapped[1], 0); - imuQuaternion.setRPY(0, cloudInfo.imu_pitch_init, 0); - tf2::Matrix3x3(transformQuaternion.slerp(imuQuaternion, imuWeight)).getRPY(rollMid, pitchMid, yawMid); - transformTobeMapped[1] = pitchMid; - } - } - - transformTobeMapped[0] = constrainRoll(transformTobeMapped[0], ROLL_TOLERANCE_RADS); - transformTobeMapped[1] = constrainPitch(transformTobeMapped[1], PITCH_TOLERANCE_RADS); - transformTobeMapped[5] = constrainZ(transformTobeMapped[5], z_tollerance); - - incrementalOdometryAffineBack = trans2Affine3f(transformTobeMapped); - } - - float constrainPitch(float value, float limit) - { - if (value < -limit){ - RCLCPP_INFO(get_logger(), "Pitch was below limit!"); - value = -limit; - } - if (value > limit) { - RCLCPP_INFO(get_logger(), "Pitch was above limit!"); - value = limit; - } - - return value; - } - float constrainZ(float value, float limit) - { - if (value < -limit){ - RCLCPP_INFO(get_logger(), "Z was below limit!"); - value = -limit; - } - if (value > limit) { - RCLCPP_INFO(get_logger(), "Z was above limit!"); - value = limit; - } - - return value; - } - float constrainRoll(float value, float limit) - { - if (value < -limit){ - RCLCPP_INFO(get_logger(), "Roll was below limit!"); - value = -limit; - } - if (value > limit) { - RCLCPP_INFO(get_logger(), "Roll was above limit!"); - value = limit; - } - - return value; - } - - bool saveFrame() - { - if (cloudKeyPoses3D->points.empty()) - return true; - - Eigen::Affine3f transStart = pclPointToAffine3f(cloudKeyPoses6D->back()); - Eigen::Affine3f transFinal = pcl::getTransformation(transformTobeMapped[3], transformTobeMapped[4], transformTobeMapped[5], - transformTobeMapped[0], transformTobeMapped[1], transformTobeMapped[2]); - Eigen::Affine3f transBetween = transStart.inverse() * transFinal; - float x, y, z, roll, pitch, yaw; - pcl::getTranslationAndEulerAngles(transBetween, x, y, z, roll, pitch, yaw); - - if (abs(roll) < surroundingkeyframeAddingAngleThreshold && - abs(pitch) < surroundingkeyframeAddingAngleThreshold && - abs(yaw) < surroundingkeyframeAddingAngleThreshold && - sqrt(x*x + y*y + z*z) < surroundingkeyframeAddingDistThreshold) - return false; - - return true; - } - - void addOdomFactor() - { - if (cloudKeyPoses3D->points.empty()) - { - noiseModel::Diagonal::shared_ptr priorNoise = noiseModel::Diagonal::Variances((Vector(6) << 1e-2, 1e-2, M_PI*M_PI, 1e8, 1e8, 1e8).finished()); // rad*rad, meter*meter - gtSAMgraph.add(PriorFactor(0, trans2gtsamPose(transformTobeMapped), priorNoise)); - initialEstimate.insert(0, trans2gtsamPose(transformTobeMapped)); - }else{ - noiseModel::Diagonal::shared_ptr odometryNoise = noiseModel::Diagonal::Variances((Vector(6) << 1e-7, 1e-7, 5e-5, 1e-2, 1e-2, 5e-2).finished()); - gtsam::Pose3 poseFrom = pclPointTogtsamPose3(cloudKeyPoses6D->points.back()); - gtsam::Pose3 poseTo = trans2gtsamPose(transformTobeMapped); - gtSAMgraph.add(BetweenFactor(cloudKeyPoses3D->size()-1, cloudKeyPoses3D->size(), poseFrom.between(poseTo), odometryNoise)); - initialEstimate.insert(cloudKeyPoses3D->size(), poseTo); - } - } - - void addGPSFactor() - { - RCLCPP_INFO(get_logger(), "Trying to add GPS"); - if (gpsQueue.empty()) { - // RCLCPP_INFO(get_logger(), "No GPS msgs in queue."); - return; - } - - // wait for system initialized and settles down - if (cloudKeyPoses3D->points.empty()){ - RCLCPP_INFO(get_logger(), "Skipping GPS. No keypoints saved."); - return; - } - else if (pointDistance(cloudKeyPoses3D->front(), cloudKeyPoses3D->back()) < 5.0){ - RCLCPP_INFO(get_logger(), "Distance too small, skipping"); - return; - } - - // pose covariance small, no need to correct - // if (poseCovariance(3,3) < poseCovThreshold && poseCovariance(4,4) < poseCovThreshold) { - // RCLCPP_WARN(get_logger(), "Skipping GPS, pose cov below threshold"); - // return; - // } - - // last gps position - static PointType lastGPSPoint; - - while (!gpsQueue.empty()) - { - if (stamp2Sec(gpsQueue.front().header.stamp) < timeLaserInfoCur - 0.5) - { - // message too old - gpsQueue.pop_front(); - RCLCPP_WARN(get_logger(), "GPS too old, skipping input"); - } - else if (stamp2Sec(gpsQueue.front().header.stamp) > timeLaserInfoCur + 0.5) - { - RCLCPP_WARN_STREAM(get_logger(), "GPS too new, should skip input: "< "< gpsCovThreshold || noise_y > gpsCovThreshold){ - RCLCPP_WARN(get_logger(), "GPS too noisy, skipping input"); - continue; - } - - float gps_x = thisGPS.pose.pose.position.x; - float gps_y = thisGPS.pose.pose.position.y; - float gps_z = thisGPS.pose.pose.position.z; - if (!useGpsElevation) - { - gps_z = transformTobeMapped[5]; - noise_z = 0.01; - } - - // GPS not properly initialized (0,0,0) - if (abs(gps_x) < 1e-6 && abs(gps_y) < 1e-6) { - RCLCPP_WARN(get_logger(), "GPS too big, skipping input"); - continue; - } - - // Add GPS every a few meters - PointType curGPSPoint; - curGPSPoint.x = gps_x; - curGPSPoint.y = gps_y; - curGPSPoint.z = gps_z; - // RCLCPP_INFO(get_logger(), "Checking GPS dist"); - if (pointDistance(curGPSPoint, lastGPSPoint) < 1.0){ - RCLCPP_WARN(get_logger(), "GPS too close, skipping input"); - continue; - } else { - lastGPSPoint = curGPSPoint; - } - - gtsam::Vector Vector3(3); - Vector3 << max(noise_x, 1.0f), max(noise_y, 1.0f), max(noise_z, 1.0f); - noiseModel::Diagonal::shared_ptr gps_noise = noiseModel::Diagonal::Variances(Vector3); - gtsam::GPSFactor gps_factor(cloudKeyPoses3D->size(), gtsam::Point3(gps_x, gps_y, gps_z), gps_noise); - float heading_x = cos(m_gpsHeading); - float heading_y = sin(m_gpsHeading); - gtsam::Vector Vector2(2); - Vector2 << max(noise_x, 1.0f), max(noise_y, 1.0f); - noiseModel::Diagonal::shared_ptr gps_heading_noise = noiseModel::Diagonal::Variances(Vector2); - gtsam::Pose3AttitudeFactor gps_heading_factor(cloudKeyPoses3D->size(), gtsam::Unit3(heading_x, heading_y, 0), gps_heading_noise); - RCLCPP_INFO(get_logger(), "ADDING GPS"); - gtSAMgraph.add(gps_factor); - gtSAMgraph.add(gps_heading_factor); - - aLoopIsClosed = true; - break; - } - } - } - - void addLoopFactor() - { - if (loopIndexQueue.empty()) - return; - - for (int i = 0; i < (int)loopIndexQueue.size(); ++i) - { - int indexFrom = loopIndexQueue[i].first; - int indexTo = loopIndexQueue[i].second; - gtsam::Pose3 poseBetween = loopPoseQueue[i]; - gtsam::noiseModel::Diagonal::shared_ptr noiseBetween = loopNoiseQueue[i]; - gtSAMgraph.add(BetweenFactor(indexFrom, indexTo, poseBetween, noiseBetween)); - } - - loopIndexQueue.clear(); - loopPoseQueue.clear(); - loopNoiseQueue.clear(); - aLoopIsClosed = true; - } - - void saveKeyFramesAndFactor() - { - // RCLCPP_INFO(get_logger(),"Adding odom, gps, loop factors"); - if (saveFrame() == false) - return; - - // odom factor - addOdomFactor(); - - // gps factor - addGPSFactor(); - - // loop factor - addLoopFactor(); - - // cout << "****************************************************" << endl; - // gtSAMgraph.print("GTSAM Graph:\n"); - - // update iSAM - isam->update(gtSAMgraph, initialEstimate); - isam->update(); - - if (aLoopIsClosed == true) - { - isam->update(); - isam->update(); - isam->update(); - isam->update(); - isam->update(); - } - - gtSAMgraph.resize(0); - initialEstimate.clear(); - - //save key poses - PointType thisPose3D; - PointTypePose thisPose6D; - Pose3 latestEstimate; - - isamCurrentEstimate = isam->calculateEstimate(); - latestEstimate = isamCurrentEstimate.at(isamCurrentEstimate.size()-1); - // cout << "****************************************************" << endl; - // isamCurrentEstimate.print("Current estimate: "); - - thisPose3D.x = latestEstimate.translation().x(); - thisPose3D.y = latestEstimate.translation().y(); - thisPose3D.z = latestEstimate.translation().z(); - thisPose3D.intensity = cloudKeyPoses3D->size(); // this can be used as index - cloudKeyPoses3D->push_back(thisPose3D); - - thisPose6D.x = thisPose3D.x; - thisPose6D.y = thisPose3D.y; - thisPose6D.z = thisPose3D.z; - thisPose6D.intensity = thisPose3D.intensity ; // this can be used as index - thisPose6D.roll = latestEstimate.rotation().roll(); - thisPose6D.pitch = latestEstimate.rotation().pitch(); - thisPose6D.yaw = latestEstimate.rotation().yaw(); - thisPose6D.time = timeLaserInfoCur; - cloudKeyPoses6D->push_back(thisPose6D); - - // cout << "****************************************************" << endl; - // cout << "Pose covariance:" << endl; - // cout << isam->marginalCovariance(isamCurrentEstimate.size()-1) << endl << endl; - poseCovariance = isam->marginalCovariance(isamCurrentEstimate.size()-1); - - // save updated transform - transformTobeMapped[0] = latestEstimate.rotation().roll(); - transformTobeMapped[1] = latestEstimate.rotation().pitch(); - transformTobeMapped[2] = latestEstimate.rotation().yaw(); - transformTobeMapped[3] = latestEstimate.translation().x(); - transformTobeMapped[4] = latestEstimate.translation().y(); - transformTobeMapped[5] = latestEstimate.translation().z(); - - // save all the received edge and surf points - pcl::PointCloud::Ptr thisCornerKeyFrame(new pcl::PointCloud()); - pcl::PointCloud::Ptr thisSurfKeyFrame(new pcl::PointCloud()); - pcl::copyPointCloud(*laserCloudCornerLastDS, *thisCornerKeyFrame); - pcl::copyPointCloud(*laserCloudSurfLastDS, *thisSurfKeyFrame); - - // save key frame cloud - cornerCloudKeyFrames.push_back(thisCornerKeyFrame); - surfCloudKeyFrames.push_back(thisSurfKeyFrame); - - // save path for visualization - updatePath(thisPose6D); - } - - void correctPoses() - { - if (cloudKeyPoses3D->points.empty()) - return; - - if (aLoopIsClosed == true) - { - // clear map cache - laserCloudMapContainer.clear(); - // clear path - globalPath.poses.clear(); - // update key poses - int numPoses = isamCurrentEstimate.size(); - for (int i = 0; i < numPoses; ++i) - { - cloudKeyPoses3D->points[i].x = isamCurrentEstimate.at(i).translation().x(); - cloudKeyPoses3D->points[i].y = isamCurrentEstimate.at(i).translation().y(); - cloudKeyPoses3D->points[i].z = isamCurrentEstimate.at(i).translation().z(); - - cloudKeyPoses6D->points[i].x = cloudKeyPoses3D->points[i].x; - cloudKeyPoses6D->points[i].y = cloudKeyPoses3D->points[i].y; - cloudKeyPoses6D->points[i].z = cloudKeyPoses3D->points[i].z; - cloudKeyPoses6D->points[i].roll = isamCurrentEstimate.at(i).rotation().roll(); - cloudKeyPoses6D->points[i].pitch = isamCurrentEstimate.at(i).rotation().pitch(); - cloudKeyPoses6D->points[i].yaw = isamCurrentEstimate.at(i).rotation().yaw(); - - updatePath(cloudKeyPoses6D->points[i]); - } - - aLoopIsClosed = false; - } - } - - void updatePath(const PointTypePose& pose_in) - { - geometry_msgs::msg::PoseStamped pose_stamped; - pose_stamped.header.stamp = rclcpp::Time(pose_in.time * 1e9); - pose_stamped.header.frame_id = odometryFrame; - pose_stamped.pose.position.x = pose_in.x; - pose_stamped.pose.position.y = pose_in.y; - pose_stamped.pose.position.z = pose_in.z; - tf2::Quaternion q; - q.setRPY(pose_in.roll, pose_in.pitch, pose_in.yaw); - pose_stamped.pose.orientation.x = q.x(); - pose_stamped.pose.orientation.y = q.y(); - pose_stamped.pose.orientation.z = q.z(); - pose_stamped.pose.orientation.w = q.w(); - - globalPath.poses.push_back(pose_stamped); - } - - void publishOdometry() - { - // Publish odometry for ROS (global) - nav_msgs::msg::Odometry laserOdometryROS; - laserOdometryROS.header.stamp = timeLaserInfoStamp; - laserOdometryROS.header.frame_id = odometryFrame; - laserOdometryROS.child_frame_id = "odom_mapping"; - laserOdometryROS.pose.pose.position.x = transformTobeMapped[3]; - laserOdometryROS.pose.pose.position.y = transformTobeMapped[4]; - laserOdometryROS.pose.pose.position.z = transformTobeMapped[5]; - tf2::Quaternion quat_tf; - quat_tf.setRPY(transformTobeMapped[0], transformTobeMapped[1], transformTobeMapped[2]); - geometry_msgs::msg::Quaternion quat_msg; - tf2::convert(quat_tf, quat_msg); - laserOdometryROS.pose.pose.orientation = quat_msg; - pubLaserOdometryGlobal->publish(laserOdometryROS); - - // Publish TF - quat_tf.setRPY(transformTobeMapped[0], transformTobeMapped[1], transformTobeMapped[2]); - tf2::Transform t_odom_to_lidar = tf2::Transform(quat_tf, tf2::Vector3(transformTobeMapped[3], transformTobeMapped[4], transformTobeMapped[5])); - tf2::TimePoint time_point = tf2_ros::fromRclcpp(timeLaserInfoStamp); - tf2::Stamped temp_odom_to_lidar(t_odom_to_lidar, time_point, odometryFrame); - geometry_msgs::msg::TransformStamped trans_odom_to_lidar; - tf2::convert(temp_odom_to_lidar, trans_odom_to_lidar); - trans_odom_to_lidar.child_frame_id = "lidar_link"; - br->sendTransform(trans_odom_to_lidar); - - // Publish odometry for ROS (incremental) - static bool lastIncreOdomPubFlag = false; - static nav_msgs::msg::Odometry laserOdomIncremental; // incremental odometry msg - static Eigen::Affine3f increOdomAffine; // incremental odometry in affine - if (lastIncreOdomPubFlag == false) - { - lastIncreOdomPubFlag = true; - laserOdomIncremental = laserOdometryROS; - increOdomAffine = trans2Affine3f(transformTobeMapped); - } else { - Eigen::Affine3f affineIncre = incrementalOdometryAffineFront.inverse() * incrementalOdometryAffineBack; - increOdomAffine = increOdomAffine * affineIncre; - float x, y, z, roll, pitch, yaw; - pcl::getTranslationAndEulerAngles (increOdomAffine, x, y, z, roll, pitch, yaw); - if (cloudInfo.imu_available == true) - { - if (std::abs(cloudInfo.imu_pitch_init) < 1.4) - { - double imuWeight = 0.1; - tf2::Quaternion imuQuaternion; - tf2::Quaternion transformQuaternion; - double rollMid, pitchMid, yawMid; - - // slerp roll - transformQuaternion.setRPY(roll, 0, 0); - imuQuaternion.setRPY(cloudInfo.imu_roll_init, 0, 0); - tf2::Matrix3x3(transformQuaternion.slerp(imuQuaternion, imuWeight)).getRPY(rollMid, pitchMid, yawMid); - roll = rollMid; - - // slerp pitch - transformQuaternion.setRPY(0, pitch, 0); - imuQuaternion.setRPY(0, cloudInfo.imu_pitch_init, 0); - tf2::Matrix3x3(transformQuaternion.slerp(imuQuaternion, imuWeight)).getRPY(rollMid, pitchMid, yawMid); - pitch = pitchMid; - } - } - laserOdomIncremental.header.stamp = timeLaserInfoStamp; - laserOdomIncremental.header.frame_id = odometryFrame; - laserOdomIncremental.child_frame_id = "odom_mapping"; - laserOdomIncremental.pose.pose.position.x = x; - laserOdomIncremental.pose.pose.position.y = y; - laserOdomIncremental.pose.pose.position.z = z; - tf2::Quaternion quat_tf; - quat_tf.setRPY(roll, pitch, yaw); - geometry_msgs::msg::Quaternion quat_msg; - tf2::convert(quat_tf, quat_msg); - laserOdomIncremental.pose.pose.orientation = quat_msg; - if (isDegenerate) - laserOdomIncremental.pose.covariance[0] = 1; - else - laserOdomIncremental.pose.covariance[0] = 0; - } - pubLaserOdometryIncremental->publish(laserOdomIncremental); - } - - void publishFrames() - { - if (cloudKeyPoses3D->points.empty()) - return; - // publish key poses - publishCloud(pubKeyPoses, cloudKeyPoses3D, timeLaserInfoStamp, odometryFrame); - // Publish surrounding key frames - publishCloud(pubRecentKeyFrames, laserCloudSurfFromMapDS, timeLaserInfoStamp, odometryFrame); - // publish registered key frame - if (pubRecentKeyFrame->get_subscription_count() != 0) - { - pcl::PointCloud::Ptr cloudOut(new pcl::PointCloud()); - PointTypePose thisPose6D = trans2PointTypePose(transformTobeMapped); - *cloudOut += *transformPointCloud(laserCloudCornerLastDS, &thisPose6D); - *cloudOut += *transformPointCloud(laserCloudSurfLastDS, &thisPose6D); - publishCloud(pubRecentKeyFrame, cloudOut, timeLaserInfoStamp, odometryFrame); - } - // publish registered high-res raw cloud - if (pubCloudRegisteredRaw->get_subscription_count() != 0) - { - pcl::PointCloud::Ptr cloudOut(new pcl::PointCloud()); - pcl::fromROSMsg(cloudInfo.cloud_deskewed, *cloudOut); - PointTypePose thisPose6D = trans2PointTypePose(transformTobeMapped); - *cloudOut = *transformPointCloud(cloudOut, &thisPose6D); - publishCloud(pubCloudRegisteredRaw, cloudOut, timeLaserInfoStamp, odometryFrame); - } - // publish path - if (pubPath->get_subscription_count() != 0) - { - globalPath.header.stamp = timeLaserInfoStamp; - globalPath.header.frame_id = odometryFrame; - pubPath->publish(globalPath); - } - } -}; - - -int main(int argc, char** argv) -{ - rclcpp::init(argc, argv); - - rclcpp::NodeOptions options; - options.use_intra_process_comms(true); - rclcpp::executors::SingleThreadedExecutor exec; - - auto MO = std::make_shared(options); - exec.add_node(MO); - - RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "\033[1;32m----> Map Optimization Started.\033[0m"); - - std::thread loopthread(&mapOptimization::loopClosureThread, MO); - std::thread visualizeMapThread(&mapOptimization::visualizeGlobalMapThread, MO); - - exec.spin(); - - rclcpp::shutdown(); - - loopthread.join(); - visualizeMapThread.join(); - - return 0; -} diff --git a/src/mapping/map_management/CMakeLists.txt b/src/mapping/map_management/CMakeLists.txt index 202b226ea..3d2e5a2de 100755 --- a/src/mapping/map_management/CMakeLists.txt +++ b/src/mapping/map_management/CMakeLists.txt @@ -14,6 +14,8 @@ cmake_minimum_required(VERSION 3.5) get_filename_component(directory_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${directory_name}) +add_library(route_manager STATIC src/RouteManager.cpp) +target_include_directories(route_manager PUBLIC include/) find_package(nova_auto_package REQUIRED) # Default to C++17 diff --git a/src/mapping/map_management/exe/map_management_node.cpp b/src/mapping/map_management/exe/map_management_node.cpp index 9a688eaba..09fbc229f 100755 --- a/src/mapping/map_management/exe/map_management_node.cpp +++ b/src/mapping/map_management/exe/map_management_node.cpp @@ -14,7 +14,7 @@ int main(int argc, char **argv) { rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); + rclcpp::spin(std::make_shared()); rclcpp::shutdown(); return 0; } diff --git a/src/mapping/map_management/include/map_management/MapManager.hpp b/src/mapping/map_management/include/map_management/MapManager.hpp index 93b9fe57e..54b52f57e 100755 --- a/src/mapping/map_management/include/map_management/MapManager.hpp +++ b/src/mapping/map_management/include/map_management/MapManager.hpp @@ -39,11 +39,17 @@ #include "carla_msgs/msg/carla_route.hpp" #include "carla_msgs/msg/carla_world_info.hpp" #include "geometry_msgs/msg/point.hpp" +#include "geometry_msgs/msg/point32.hpp" +#include "geometry_msgs/msg/polygon_stamped.hpp" #include "geometry_msgs/msg/pose_stamped.hpp" #include "geometry_msgs/msg/transform_stamped.hpp" +#include "nav_msgs/msg/map_meta_data.hpp" #include "nav_msgs/msg/occupancy_grid.hpp" #include "nav_msgs/msg/path.hpp" #include "rosgraph_msgs/msg/clock.hpp" +#include "std_msgs/msg/float32.hpp" + +#include "map_management/RouteManager.hpp" using namespace std::chrono_literals; using namespace nav_msgs::msg; @@ -53,13 +59,15 @@ namespace bgi = boost::geometry::index; using carla_msgs::msg::CarlaRoute; using carla_msgs::msg::CarlaWorldInfo; using PointMsg = geometry_msgs::msg::Point; +using geometry_msgs::msg::Point32; +using geometry_msgs::msg::PolygonStamped; using geometry_msgs::msg::PoseStamped; using geometry_msgs::msg::TransformStamped; using rosgraph_msgs::msg::Clock; namespace navigator { - namespace perception + namespace planning { class MapManagementNode : public rclcpp::Node @@ -69,30 +77,43 @@ namespace navigator MapManagementNode(); // Functions - OccupancyGrid getDrivableAreaGrid(PointMsg center, int range, float res); + void publishGrids(int top, int bottom, int side, float res); private: // Parameters // TODO: Convert to ros params std::chrono::milliseconds GRID_PUBLISH_FREQUENCY = 200ms; - const int GRID_RANGE = 40; + std::chrono::milliseconds ROUTE_PUBLISH_FREQUENCY = 240ms; + std::chrono::milliseconds TRAFFIC_LIGHT_PUBLISH_FREQUENCY = 5000ms; + const int GRID_RANGE = 30; const float GRID_RES = 0.4; void clockCb(Clock::SharedPtr msg); TransformStamped getVehicleTf(); void drivableAreaGridPubTimerCb(); - void refineRoughPath(Path::SharedPtr msg); - void routeDistanceGridPubTimerCb(); + void updateRouteWaypoints(Path::SharedPtr msg); + void publishRefinedRoute(); void worldInfoCb(CarlaWorldInfo::SharedPtr msg); + std::map getJunctionMap(std::vector lane_polys); + + LineString getLaneCenterline(odr::LaneKey key); + std::vector getCenterlinesFromKeys(std::vector keys, odr::RoutingGraph graph); - rclcpp::Publisher::SharedPtr grid_pub_; + rclcpp::Publisher::SharedPtr drivable_grid_pub_; + rclcpp::Publisher::SharedPtr junction_grid_pub_; + rclcpp::Publisher::SharedPtr route_dist_grid_pub_; rclcpp::Publisher::SharedPtr route_path_pub_; + rclcpp::Publisher::SharedPtr route_progress_pub_; + rclcpp::Publisher::SharedPtr traffic_light_points_pub_; + rclcpp::Publisher::SharedPtr goal_pose_pub_; rclcpp::Subscription::SharedPtr clock_sub; rclcpp::Subscription::SharedPtr rough_path_sub_; rclcpp::Subscription::SharedPtr world_info_sub; rclcpp::TimerBase::SharedPtr drivable_area_grid_pub_timer_; rclcpp::TimerBase::SharedPtr route_distance_grid_pub_timer_; + rclcpp::TimerBase::SharedPtr traffic_light_pub_timer_; + rclcpp::TimerBase::SharedPtr route_timer_; std::shared_ptr tf_listener_{nullptr}; std::unique_ptr tf_buffer_; @@ -101,8 +122,17 @@ namespace navigator odr::OpenDriveMap *map_ = nullptr; std::vector lane_polys_; std::vector lanes_in_route_; - Path smoothed_path_msg_; + std::map road_in_junction_map_; + Path smoothed_route_msg_; + LineString rough_route_; + Path rough_route_msg_; + bg::model::linestring route_linestring_; + bg::model::linestring local_route_linestring_; bgi::rtree> map_wide_tree_; + bgi::rtree> rough_route_tree_; + PolygonStamped traffic_light_points; + + RouteManager rm; }; } -} +} \ No newline at end of file diff --git a/src/mapping/map_management/include/map_management/RouteManager.hpp b/src/mapping/map_management/include/map_management/RouteManager.hpp new file mode 100644 index 000000000..eaa4670d9 --- /dev/null +++ b/src/mapping/map_management/include/map_management/RouteManager.hpp @@ -0,0 +1,47 @@ +/* + * Package: map_management + * Filename: RouteManager.hpp + * Author: Will Heitman + * Email: w at heit dot mn + * Copyright: 2023, Nova UTD + * License: MIT License + * + * Simple class to refine and update routes + */ + +#pragma once + +#include // Time literals +#include +#include + +// Boost +#include +#include +#include +#include +#include +#include +#include + +using namespace std::chrono_literals; +namespace bg = boost::geometry; +namespace bgi = boost::geometry::index; + +namespace navigator +{ + namespace planning + { + typedef bg::model::point BoostPoint; + typedef boost::geometry::model::linestring LineString; + + class RouteManager + { + public: + // Constructor + RouteManager(); + + LineString getRoute(const LineString rough, const BoostPoint pos); + }; + } +} \ No newline at end of file diff --git a/src/mapping/map_management/package.xml b/src/mapping/map_management/package.xml index a49fdcac8..4258b20ce 100755 --- a/src/mapping/map_management/package.xml +++ b/src/mapping/map_management/package.xml @@ -15,6 +15,7 @@ geometry_msgs libopendrive nav_msgs + nova_msgs rosgraph_msgs tf2 tf2_ros diff --git a/src/mapping/map_management/src/MapManager.cpp b/src/mapping/map_management/src/MapManager.cpp index fc5528bc8..1955cb9be 100755 --- a/src/mapping/map_management/src/MapManager.cpp +++ b/src/mapping/map_management/src/MapManager.cpp @@ -17,20 +17,32 @@ #include -using namespace navigator::perception; +using namespace navigator::planning; + +struct RoiIndices +{ + int start = -1; + int center = -1; + int end = -1; +}; MapManagementNode::MapManagementNode() : Node("map_management_node") { // Publishers and subscribers - grid_pub_ = this->create_publisher("/grid/drivable", 10); - route_path_pub_ = this->create_publisher("/route/smooth_path", 10); + drivable_grid_pub_ = this->create_publisher("/grid/drivable", 10); + junction_grid_pub_ = this->create_publisher("/grid/junction", 10); + route_dist_grid_pub_ = this->create_publisher("/grid/route_distance", 10); + route_path_pub_ = this->create_publisher("/planning/smooth_route", 10); + traffic_light_points_pub_ = this->create_publisher("/traffic_light_points", 10); + goal_pose_pub_ = this->create_publisher("/planning/goal_pose", 1); + route_progress_pub_ = this->create_publisher("/route_progress", 1); clock_sub = this->create_subscription("/clock", 10, bind(&MapManagementNode::clockCb, this, std::placeholders::_1)); - rough_path_sub_ = this->create_subscription("/route/rough_path", 10, bind(&MapManagementNode::refineRoughPath, this, std::placeholders::_1)); + rough_path_sub_ = this->create_subscription("/planning/rough_route", 10, bind(&MapManagementNode::updateRouteWaypoints, this, std::placeholders::_1)); world_info_sub = this->create_subscription("/carla/world_info", 10, bind(&MapManagementNode::worldInfoCb, this, std::placeholders::_1)); drivable_area_grid_pub_timer_ = this->create_wall_timer(GRID_PUBLISH_FREQUENCY, bind(&MapManagementNode::drivableAreaGridPubTimerCb, this)); - route_distance_grid_pub_timer_ = this->create_wall_timer(GRID_PUBLISH_FREQUENCY, bind(&MapManagementNode::routeDistanceGridPubTimerCb, this)); + route_timer_ = this->create_wall_timer(ROUTE_PUBLISH_FREQUENCY, bind(&MapManagementNode::publishRefinedRoute, this)); tf_buffer_ = std::make_unique(this->get_clock()); tf_listener_ = std::make_shared(*tf_buffer_); @@ -48,38 +60,53 @@ MapManagementNode::MapManagementNode() : Node("map_management_node") * 4. Set OccupancyGrid metadata and return. * * @param center Center of the grid - * @param range Radius in meters + * @param top_dist Distance from car to top edge + * @param bottom_dist Distance from car to bottom edge + * @param side_dist Distance from car to left and right edges * @param res Side length of grid cells (meters) * @return OccupancyGrid */ -OccupancyGrid navigator::perception::MapManagementNode::getDrivableAreaGrid(PointMsg center, int range, float res) +void MapManagementNode::publishGrids(int top_dist, int bottom_dist, int side_dist, float res) { if (this->map_ == nullptr) { RCLCPP_INFO_THROTTLE(this->get_logger(), *this->get_clock(), 5000, "Map not yet loaded. Drivable area grid is unavailable."); - return OccupancyGrid(); + return; } + // printf("Publish grids... "); + // Used to calculate function runtime std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); - OccupancyGrid occupancy_grid; - std::vector grid_data; - - int grid_radius_in_cells = std::ceil(range / res); + OccupancyGrid drivable_area_grid; + OccupancyGrid junction_grid; + OccupancyGrid route_dist_grid; + MapMetaData grid_info; + std::vector drivable_grid_data; + std::vector junction_grid_data; + std::vector route_dist_grid_data; - float x_min = center.x - range; - float x_max = center.x + range; - float y_min = center.y - range; - float y_max = center.y + range; + float y_min = side_dist * -1; + float y_max = side_dist; + float x_min = bottom_dist * -1; + float x_max = top_dist; // std::printf("[%f, %f], [%f, %f], %f\n", x_min, x_max, y_min, y_max, res); if (this->map_wide_tree_.size() == 0) this->map_wide_tree_ = this->map_->generate_mesh_tree(); - odr::box search_region(odr::point(x_min, y_min), odr::point(x_max, y_max)); + // Get the search region + TransformStamped vehicle_tf = getVehicleTf(); + auto vehicle_pos = vehicle_tf.transform.translation; + double range_plus = top_dist * 1.4; // This is a little leeway to account for map->base_link rotation + odr::point bounding_box_min = odr::point(vehicle_pos.x - range_plus, vehicle_pos.y - range_plus); + odr::point bounding_box_max = odr::point(vehicle_pos.x + range_plus, vehicle_pos.y + range_plus); + odr::box search_region(bounding_box_min, bounding_box_max); + + // Find all lanes within the search region std::vector lane_shapes_in_range; map_wide_tree_.query(bgi::intersects(search_region), std::back_inserter(lane_shapes_in_range)); @@ -95,6 +122,19 @@ OccupancyGrid navigator::perception::MapManagementNode::getDrivableAreaGrid(Poin int area = 0; int height = 0; + BoostPoint goal_pt; + bool goal_is_set = false; + auto q = vehicle_tf.transform.rotation; + float h; + + if (q.z < 0) + h = abs(2 * acos(q.w) - 2 * M_PI); + else + h = 2 * acos(q.w); + + if (h > M_PI) + h -= 2 * M_PI; + for (float j = y_min; j <= y_max; j += res) { for (float i = x_min; i <= x_max; i += res) @@ -102,9 +142,20 @@ OccupancyGrid navigator::perception::MapManagementNode::getDrivableAreaGrid(Poin i = static_cast(i); j = static_cast(j); - bool cell_is_occupied = false; + bool cell_is_drivable = false; + bool cell_is_in_junction = false; + + // Transform this query into the map frame + // First rotate, then translate. 2D rotation eq: + // x' = xcos(h) - ysin(h) + // y' = ycos(h) + xsin(h) - odr::point p(i, j); + // if (h < 0) + // h += 2 * M_PI; + float i_in_map = i * cos(h) - j * sin(h) + vehicle_pos.x; + float j_in_map = j * cos(h) + i * sin(h) + vehicle_pos.y; + + odr::point p(i_in_map, j_in_map); std::vector local_tree_query_results; local_tree.query(bgi::contains(p), std::back_inserter(local_tree_query_results)); @@ -113,44 +164,95 @@ OccupancyGrid navigator::perception::MapManagementNode::getDrivableAreaGrid(Poin { for (auto pair : local_tree_query_results) { + // auto pair = local_tree_query_results.front(); odr::ring ring = this->lane_polys_.at(pair.second).second; + odr::Lane lane = this->lane_polys_.at(pair.second).first; + // odr::Road road = this->map_->id_to_road.at(lane.key.road_id); bool point_is_within_shape = bg::within(p, ring); if (point_is_within_shape) { - cell_is_occupied = true; - break; + cell_is_in_junction = this->road_in_junction_map_[lane.key]; + if (lane.type == "driving") + { + cell_is_drivable = true; + break; + } } } } - if (cell_is_occupied) - grid_data.push_back(100); + drivable_grid_data.push_back(cell_is_drivable ? 0 : 100); + junction_grid_data.push_back(cell_is_in_junction ? 100 : 0); + + // Get closest route point + if (local_route_linestring_.size() > 0 && cell_is_drivable && i > 0) + { + int dist = static_cast(bg::distance(local_route_linestring_, p) * 8); + + if (dist < 1.0 && !goal_is_set && abs(i) + abs(j) > 30) + { + goal_is_set = true; + goal_pt = BoostPoint(i, j); + } + + // Distances > 10 are set to 100 + if (dist > 20) + dist = 100; + else + dist *= 5; + + route_dist_grid_data.push_back(dist); + } else - grid_data.push_back(0); + { + route_dist_grid_data.push_back(100); + } area += 1; } height += 1; } - // Set the OccupancyGrid's metadata auto clock = this->clock_->clock; - occupancy_grid.data = grid_data; - occupancy_grid.header.frame_id = "map"; - occupancy_grid.header.stamp = clock; - occupancy_grid.info.width = area / height; - occupancy_grid.info.height = height; - occupancy_grid.info.map_load_time = clock; - occupancy_grid.info.resolution = GRID_RES; - occupancy_grid.info.origin.position.x = x_min; - occupancy_grid.info.origin.position.y = y_min; + drivable_area_grid.data = drivable_grid_data; + drivable_area_grid.header.frame_id = "base_link"; + drivable_area_grid.header.stamp = clock; + + junction_grid.data = junction_grid_data; + junction_grid.header.frame_id = "base_link"; + junction_grid.header.stamp = clock; + + route_dist_grid.data = route_dist_grid_data; + route_dist_grid.header.frame_id = "base_link"; + route_dist_grid.header.stamp = clock; + + grid_info.width = area / height; + grid_info.height = height; + grid_info.map_load_time = clock; + grid_info.resolution = res; + grid_info.origin.position.x = x_min; + grid_info.origin.position.y = y_min; + + // Set the grids' metadata + drivable_area_grid.info = grid_info; + junction_grid.info = grid_info; + route_dist_grid.info = grid_info; // Output function runtime - std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); - // std::cout << "Time difference = " << std::chrono::duration_cast(end - begin).count() << "[ms]" << std::endl; + drivable_grid_pub_->publish(drivable_area_grid); + junction_grid_pub_->publish(junction_grid); + route_dist_grid_pub_->publish(route_dist_grid); // Route distance grid - return occupancy_grid; + PoseStamped goal_pose; + goal_pose.pose.position.x = goal_pt.get<0>(); + goal_pose.pose.position.y = goal_pt.get<1>(); + goal_pose.header.frame_id = "base_link"; + goal_pose.header.stamp = clock_->clock; + goal_pose_pub_->publish(goal_pose); + + std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + // std::cout << "publishGrids(): " << std::chrono::duration_cast(end - begin).count() << "[ms]" << std::endl; } /** @@ -158,7 +260,7 @@ OccupancyGrid navigator::perception::MapManagementNode::getDrivableAreaGrid(Poin * * @param msg */ -void navigator::perception::MapManagementNode::clockCb(Clock::SharedPtr msg) +void MapManagementNode::clockCb(Clock::SharedPtr msg) { this->clock_ = msg; } @@ -168,7 +270,7 @@ void navigator::perception::MapManagementNode::clockCb(Clock::SharedPtr msg) * * @return TransformStamped */ -TransformStamped navigator::perception::MapManagementNode::getVehicleTf() +TransformStamped MapManagementNode::getVehicleTf() { TransformStamped t; try @@ -190,245 +292,411 @@ TransformStamped navigator::perception::MapManagementNode::getVehicleTf() * @brief Gets the drivable area OccupancyGrid and publishes it. * */ -void navigator::perception::MapManagementNode::drivableAreaGridPubTimerCb() +void MapManagementNode::drivableAreaGridPubTimerCb() { - TransformStamped t = getVehicleTf(); + // std::printf("Publishing grids\n"); + publishGrids(40, 20, 30, 0.4); +} - PointMsg center; - center.x = t.transform.translation.x; - center.y = t.transform.translation.y; +// CPP code for printing shortest path between +// two vertices of unweighted graph +#include +using namespace std; - OccupancyGrid msg = getDrivableAreaGrid(center, GRID_RANGE, GRID_RES); - grid_pub_->publish(msg); +// utility function to form edge between two vertices +// source and dest +void add_edge(vector adj[], int src, int dest) +{ + adj[src].push_back(dest); + adj[dest].push_back(src); } /** - * @brief Refine a rough path from CARLA into a smooth, sub-meter accurate path - * - * 1. For each pose in the rough path, use an RTree to find the matching lane in the map - * 2. Given the sequence of lanes, fill in gaps and validate using libOpenDRIVE's routing graph - * a. This is very, very slow, but it should guarantee a valid lane sequence. - * b. This accounts for junctions, where a point may belong to >1 lane. - * 3. For each lane in the sequence, sample the centerline and add this point to a boost linestring - * a. This creates a continuous Cartesian curve - * 4. Pusblish this refined curve as a Path message. - * - * @param msg + * @brief Simple breadth-first search using libOpenDRIVE's inbuilt routing graph. + * Undirected! See https://en.wikipedia.org/wiki/Breadth-first_search#Pseudocode + * + * @param source + * @param dest + * @param graph + * @return std::unordered_map */ -void navigator::perception::MapManagementNode::refineRoughPath(Path::SharedPtr msg) +std::unordered_map bfs(odr::LaneKey source, odr::LaneKey dest, odr::RoutingGraph graph) { - if (this->map_ == nullptr) - return; - if (this->smoothed_path_msg_.poses.size() > 0) + std::unordered_set visited_lanes; + std::unordered_map parents; + visited_lanes.insert(source); + std::vector route; + std::queue queue; + + queue.push(source); + while (!queue.empty()) { - // RCLCPP_WARN(this->get_logger(), "Lanes already calculated from rough path."); - route_path_pub_->publish(smoothed_path_msg_); - return; + odr::LaneKey v = queue.front(); + queue.pop(); + + if (v.to_string() == dest.to_string()) + { + return parents; + } + + for (auto w : graph.get_lane_predecessors(v)) + { + if (visited_lanes.find(w) == visited_lanes.end()) + { + visited_lanes.insert(w); + parents.insert(std::make_pair(w, v)); + queue.push(w); + } + } + for (auto w : graph.get_lane_successors(v)) + { + if (visited_lanes.find(w) == visited_lanes.end()) + { + visited_lanes.insert(w); + parents.insert(std::make_pair(w, v)); + queue.push(w); + } + } } + // RCLCPP_ERROR(get_logger(), "Destination not found"); + return parents; +} - std::vector lanes_in_route; +LineString getSmoothSection(LineString full_route, BoostPoint ego, int &start_idx, int &end_idx) +{ - RCLCPP_INFO(this->get_logger(), "Processing rough path with %i poses", msg->poses.size()); + // Get closest waypoint in full_route + float closest_dist = 999.9; + int closest_idx = -1; - for (auto pose : msg->poses) + for (int i = 0; i < full_route.size(); i++) { - auto position = pose.pose.position; - // Find the lane polygon(s) that the point falls within - odr::point p(position.x, position.y); - std::vector query_results; - std::vector lanes_containing_point; + auto wp = full_route[i]; + float dist_to_ego = bg::distance(ego, wp); + if (dist_to_ego < closest_dist) + { + closest_dist = dist_to_ego; + closest_idx = i; + } + } - this->map_wide_tree_.query(bgi::contains(p), std::back_inserter(query_results)); + end_idx = closest_idx < 1 ? closest_idx : closest_idx - 1; - // RCLCPP_INFO(this->get_logger(), "Query returned %i results", query_results.size()); + LineString rough_section; + start_idx = closest_idx + 1; + float edge_distance = closest_dist; - for (auto result : query_results) - { - /* - lane_polys_ is a vector of LanePairs, where a LanePair - has a Lane object (which contains details like the lane ID, parent road, etc), - and a ring (a Boost geometry that describes the outline of the lane). + // Find the "edge" waypoint + // That's the divider between the smooth and rough route sections + // It should be > 40m from the ego + while (edge_distance < 40.0) + { + auto wp = full_route[start_idx]; + edge_distance = bg::distance(ego, wp); + start_idx++; + } - A "result" contains a given lane ring's bounding box (first) and - the index of the ring (result.second). This is the same index within - lane_polys_. Adding ".first" gets the Lane object. + return rough_section; +} - Got that? - */ +LineString MapManagementNode::getLaneCenterline(odr::LaneKey key) +{ + LineString centerline; - odr::ring ring = this->lane_polys_.at(result.second).second; - if (bg::within(p, ring)) - { - odr::Lane containing_lane = this->lane_polys_.at(result.second).first; + odr::Road road = map_->id_to_road.at(key.road_id); + odr::LaneSection lsec = road.s_to_lanesection.at(key.lanesection_s0); + odr::Lane lane = lsec.id_to_lane.at(key.lane_id); - auto parent_road = this->map_->id_to_road.at(containing_lane.key.road_id); - if (parent_road.junction != "-1") - continue; // Junction found! Skip this lane. + odr::Line3D outer_border = road.get_lane_border_line(lane, 1.0, true); + odr::Line3D inner_border = road.get_lane_border_line(lane, 1.0, false); - lanes_containing_point.push_back(containing_lane); - } - } + for (int i = 0; i < outer_border.size(); i++) + { + odr::Vec3D outer_pt = outer_border[i]; + odr::Vec3D inner_pt = inner_border[i]; + BoostPoint center_pt((outer_pt[0] + inner_pt[0]) / 2, (outer_pt[1] + inner_pt[1]) / 2); + bg::append(centerline, center_pt); + } + + return centerline; +} + +LineString getReorientedRoute(std::vector centerlines) +{ + LineString result; + + auto iter = centerlines.begin(); + while (iter != centerlines.end() - 1) + { + // Get end of this segment and the beginning of the next one + // Check the distance between them. + // If distance is small, the orientation is correct. Continue. + // If distance is large, reverse order of next segment + + const float MAX_ENDPOINT_GAP = 2.0; // meters - // Does this point fall within more than one lane? - // If so, we've found a junction. Skip to next pose. - // if (lanes_containing_point.size() > 1) - // { - // RCLCPP_INFO(this->get_logger(), "Point (%f, %f) falls within a junction. Skipping.", position.x, position.y); - // continue; - // } - if (lanes_containing_point.size() < 1) + auto current_end = iter->back(); + auto next_begin = (iter + 1)->front(); + float dist = bg::distance(current_end, next_begin); + + // std::printf("Distance was %f. ", dist); + + if (dist > MAX_ENDPOINT_GAP) { - RCLCPP_INFO(this->get_logger(), "Point (%f, %f) does not fall within a lane. Skipping.", position.x, position.y); - continue; + bg::reverse(*(iter + 1)); } - // Append the matching lane to the full route - lanes_in_route.push_back(lanes_containing_point.front()); + next_begin = (iter + 1)->front(); + // dist = bg::distance(current_end, next_begin); + // std::printf("Distance is now %f.\n", dist); + + bg::append(result, *iter); + + iter++; } + bg::append(result, centerlines.back()); - this->lanes_in_route_ = lanes_in_route; + return result; +} - smoothed_path_msg_.poses.clear(); - smoothed_path_msg_.header.frame_id = "map"; - smoothed_path_msg_.header.stamp = this->clock_->clock; +void MapManagementNode::updateRouteWaypoints(Path::SharedPtr msg) +{ + if (rough_route_tree_.size() > 0 && rough_route_tree_.size() == msg->poses.size()) + { + // It looks like we've already processed a route and the new route as the same size. + // If the new route's size and the current tree's size are the same, + // we can assume that the incoming route is not new. + return; + } + + // Let's build an RTree to efficiently represent the new waypoints. + + rough_route_tree_.clear(); + rough_route_.clear(); + + for (unsigned i = 0; i < msg->poses.size(); ++i) + { + PoseStamped wp_pose = msg->poses[i]; + + BoostPoint wp(wp_pose.pose.position.x, wp_pose.pose.position.y); + rough_route_tree_.insert(std::make_pair(bg::return_envelope(wp), i)); + bg::append(rough_route_, wp); + } + + RCLCPP_INFO(get_logger(), "%i waypoints added to tree", rough_route_tree_.size()); +} - auto routing_graph = this->map_->get_routing_graph(); +RoiIndices getWaypointsInROI(LineString waypoints, bgi::rtree> tree, BoostPoint ego_pos) +{ + std::vector returned_values; + // Query our tree. "1" means get the single nearest waypoint + tree.query(bgi::nearest(ego_pos, 1), std::back_inserter(returned_values)); + int nearest_idx = returned_values.front().second; - std::vector complete_route; - int progress_counter = 0; - const int ITER_LIMIT = 10; - for (auto it = lanes_in_route.begin(); it < lanes_in_route.end() - 1; it++) + // Go backward in rough route until either + // a) We hit the route's start or + // b) we're >40m from ego + // Get idx of last waypoint visited + auto iter = waypoints.begin() + nearest_idx; + int start_idx = nearest_idx; + while (iter != waypoints.begin()) { - printf("%i/%i\n", progress_counter, lanes_in_route.size()); - progress_counter++; + start_idx--; + iter--; + if (bg::distance(ego_pos, *iter) > 40.0) + break; + } - if (progress_counter > ITER_LIMIT) + // Go forward in rough route until either + // a) We hit the route's end or + // b) we're >40m from ego + // Get idx of last waypoint visited + iter = waypoints.begin() + nearest_idx; + int end_idx = nearest_idx; + while (iter != waypoints.end()) + { + end_idx++; + iter++; + if (bg::distance(ego_pos, *iter) > 40.0) break; + } - if (it->key.to_string() == (it + 1)->key.to_string()) - { - // printf("Keys were the same. Skipping.\n"); - continue; - } - std::vector route = routing_graph.shortest_path((it + 1)->key, it->key); + // RCLCPP_INFO(get_logger(), "(%i, %i, %i)", start_idx, nearest_idx, end_idx); - // Reverse the order of the route - std::reverse(route.begin(), route.end()); + RoiIndices result; + result.center = nearest_idx; + result.start = start_idx; + result.end = end_idx; - if (route.size() < 2) - { - // RCLCPP_WARN(this->get_logger(), "Route not found. Trying other direction."); - route = routing_graph.shortest_path(it->key, (it + 1)->key); - if (route.size() < 2) - { - RCLCPP_WARN(this->get_logger(), "Route not found."); - continue; - } - } - for (auto key : route) - { - if (complete_route.size() > 0 && key.to_string() == complete_route.back().to_string()) - { - continue; - } + return result; +} - complete_route.push_back(key); - } +std::vector getLaneKeysFromIndices(RoiIndices indices, LineString waypoints, bgi::rtree> lane_tree, std::vector lane_polys) +{ + LineString waypoints_within_roi; + // bg::simplify(waypoints, simplified_wps, 5.0); - if (progress_counter % 10 == 0) - { - for (auto key : complete_route) - { - printf("%s\n", key.to_string().c_str()); - } - } + for (int i = indices.start; i <= indices.end; i++) + { + bg::append(waypoints_within_roi, waypoints[i]); } - // For each LaneKey in Route, linear sample and append to vector - bg::model::linestring route_linestring; + // Simplification downsamples the linestring, speeding us up a bit + LineString simplified_wpts; + bg::simplify(waypoints_within_roi, simplified_wpts, 5.0); - odr::point latest_point; + std::vector query_results; - for (auto key : complete_route) + // For each wp, find it in the lane_tree + for (auto pt : simplified_wpts) { - // printf("%s\n", key.to_string().c_str()); - odr::Road road = this->map_->id_to_road.at(key.road_id); - // printf("Road was %s\n", road.id.c_str()); - odr::LaneSection lsec = road.get_lanesection(key.lanesection_s0); - // printf("Lsec was %f\n", lsec.s0); - // for (auto lane : lsec.get_lanes()) - // { - // printf("%i ", lane.id); - // } - printf("\n"); - odr::Lane lane = lsec.id_to_lane.at(key.lane_id); - // printf("Lane was %i\n", lane.id); - - odr::Line3D line = road.get_lane_border_line(lane, 1.0, true); - - // Test to see if the direction of this lane needs to be reversed - if (route_linestring.size() > 0) - { + lane_tree.query(bgi::intersects(pt), std::back_inserter(query_results)); + } - odr::point first_pt_in_lane = odr::point(line.front()[0], line.front()[1]); - double dist = bg::distance(latest_point, first_pt_in_lane); - printf("Distance was %f\n", dist); + std::vector lane_keys; - if (dist > 30) { - std::reverse(line.begin(), line.end()); - odr::point first_pt_in_lane = odr::point(line.front()[0], line.front()[1]); - double dist = bg::distance(latest_point, first_pt_in_lane); - printf("Distance is now %f\n", dist); - } - - - } else { - latest_point = odr::point(line.front()[0], line.front()[1]); - } + // Move through our tree search results, extracting the lane key and + // adding it to our result list. + for (auto result : query_results) + { + odr::LanePair result_pair = lane_polys[result.second]; + lane_keys.push_back(result_pair.first.key); + // std::printf("%s\n", result_pair.first.key.to_string().c_str()); + } + + return lane_keys; +} + +std::vector MapManagementNode::getCenterlinesFromKeys(std::vector keys, odr::RoutingGraph graph) +{ + + // Move from first to second-to-last key. + // Use VFS to find route from this key to the next one, + // collectively forming a route chain connecting each waypoint's parent lane + + std::vector complete_keys; // keys, but with gaps in lanes filled. + + // Loop starts at last key and works to the first key + for (auto iter = keys.end() - 1; iter != keys.begin(); iter--) + { + std::vector complete_segment; // keys, but with gaps in lanes filled. + odr::LaneKey from = *iter; + odr::LaneKey to = *(iter - 1); + // std::printf("(%s)=>(%s)\n", from.to_string().c_str(), to.to_string().c_str()); + if (from.to_string() == to.to_string()) // Keys have the same lane + continue; + auto adjacency_pairs = bfs(from, to, graph); + // std::printf("BFS returned %i pairs\n", adjacency_pairs.size()); + + complete_segment.push_back(to); - for (odr::Vec3D pt : line) + // Work our way back from destination to source in the tree search, + // producing a continuous LaneKey route. + try { - odr::point boost_point(pt[0], pt[1]); - bg::append(route_linestring, boost_point); - printf("Adding point (%f, %f)\n", pt[0], pt[1]); - latest_point = boost_point; + odr::LaneKey parent = adjacency_pairs.at(to); + do + { + complete_segment.push_back(parent); + parent = adjacency_pairs.at(parent); + } while (parent.to_string() != from.to_string()); } + catch (...) + { + // RCLCPP_ERROR(get_logger(), "BFS could not locate route parent. Returning."); + } + + complete_keys.insert(complete_keys.begin(), complete_segment.begin(), complete_segment.end()); } - // Publish route as Path msg - smoothed_path_msg_.header.stamp = this->clock_->clock; - smoothed_path_msg_.header.frame_id = "map"; + // The final key is left out of above. Add it now. + complete_keys.push_back(keys.back()); - smoothed_path_msg_.poses.clear(); - for (odr::point pt : route_linestring) + // We now have a continuous LaneKey sequence that connects all provided Keys. + std::vector centerlines; + for (auto key : complete_keys) { - PoseStamped pose_msg; - pose_msg.pose.position.x = pt.get<0>(); - pose_msg.pose.position.y = pt.get<1>(); - smoothed_path_msg_.poses.push_back(pose_msg); - } + // std::printf("%s\n", key.to_string().c_str()); - route_path_pub_->publish(smoothed_path_msg_); + LineString centerline = getLaneCenterline(key); + centerlines.push_back(centerline); + } - RCLCPP_INFO(this->get_logger(), "Publishing path with %i poses. Started with %i poses.\n", smoothed_path_msg_.poses.size(), msg->poses.size()); + return centerlines; } /** - * @brief Generate and publish the "distance from route" cost map layer + * @brief Given rough waypoints, turn them into a smooth, local curve + * of continuous lane centerlines. + * + * 1. Crop waypoints to those nearby (<40m, plus 1-waypoint buffer on either end) + * 2. Convert waypoints to matching lanes (odr::LaneKeys) + * 3. Convert LaneKeys to LineStrings from BoostGeometry + * 4. Reorient these LineStrings so that their ends line up. Combine them into a single curve. + * 5. Convert the final LineString to a path message. * */ -void navigator::perception::MapManagementNode::routeDistanceGridPubTimerCb() +void MapManagementNode::publishRefinedRoute() { - TransformStamped t = getVehicleTf(); - - if (this->smoothed_path_msg_.poses.size() < 1) { - RCLCPP_WARN(get_logger(), "Refined route not yet calculated. Skipping."); + if (rough_route_tree_.empty() || map_wide_tree_.empty()) return; + + // Get waypoint closest to ego + auto ego_tf = getVehicleTf(); + BoostPoint ego_pos(ego_tf.transform.translation.x, ego_tf.transform.translation.y); + + // Get indices of waypoint ROI + RoiIndices waypoint_roi = getWaypointsInROI(rough_route_, rough_route_tree_, ego_pos); + + // Let's take a moment to publish our route progress using this info + float route_progress = static_cast(waypoint_roi.center) / rough_route_.size(); + std_msgs::msg::Float32 progress_msg; + progress_msg.data = route_progress; + route_progress_pub_->publish(progress_msg); + + // Get LaneKeys + std::vector keys = getLaneKeysFromIndices(waypoint_roi, rough_route_, map_wide_tree_, lane_polys_); + + // Get centerlines + auto centerlines = getCenterlinesFromKeys(keys, map_->get_routing_graph()); + + // Orient them so that their ends and beginnings properly match + LineString route_ls = getReorientedRoute(centerlines); + bg::simplify(route_ls, local_route_linestring_, 1.0); + + // Convert to ROS message + Path result; + result.header.frame_id = "map"; + result.header.stamp = clock_->clock; + for (auto pt : route_ls) + { + PoseStamped pose; + pose.pose.position.x = pt.get<0>(); + pose.pose.position.y = pt.get<1>(); + pose.header.frame_id = "map"; + pose.header.stamp = clock_->clock; + result.poses.push_back(pose); } - // Trim the route to all points ahead of the car. + route_path_pub_->publish(result); +} + +std::map MapManagementNode::getJunctionMap(std::vector lane_polys) +{ + std::map map; + for (auto pair : lane_polys) + { + odr::Lane lane = pair.first; + odr::Road road = this->map_->id_to_road.at(lane.key.road_id); + if (road.junction != "-1" && lane.type == "driving") + map[lane.key] = true; + else + map[lane.key] = false; + } + + return map; } /** @@ -449,7 +717,9 @@ void MapManagementNode::worldInfoCb(CarlaWorldInfo::SharedPtr msg) // Ask libopendrive to parse the map string this->map_ = new odr::OpenDriveMap(msg->opendrive, true); // Get lane polygons as pairs (Lane object, ring polygon) - this->lane_polys_ = map_->get_lane_polygons(1.0); + this->lane_polys_ = map_->get_lane_polygons(1.0, false); - RCLCPP_INFO(this->get_logger(), "Loaded %s", msg->map_name); -} + this->road_in_junction_map_ = this->getJunctionMap(this->lane_polys_); + + RCLCPP_INFO(this->get_logger(), "Loaded %s", msg->map_name.c_str()); +} \ No newline at end of file diff --git a/src/mapping/map_management/src/RouteManager.cpp b/src/mapping/map_management/src/RouteManager.cpp new file mode 100644 index 000000000..ee75df5c1 --- /dev/null +++ b/src/mapping/map_management/src/RouteManager.cpp @@ -0,0 +1,19 @@ +#include "map_management/RouteManager.hpp" + +using namespace navigator::planning; + +RouteManager::RouteManager() +{ +} + +/** + * @brief Returns a refined route given current position and the rough route + * + * @param rough A rough route, with a minimum of two waypoints + * @param pos Our current position + * @return A refined path, with smooth and rough sections, and with the route behind us removed. + */ +LineString RouteManager::getRoute(const LineString rough, const BoostPoint pos) +{ + std::printf("Rough route has %i waypoints\n", rough.size()); +} \ No newline at end of file diff --git a/src/mapping/map_management_old/map_management/map_management_node.py b/src/mapping/map_management_old/map_management/map_management_node.py deleted file mode 100755 index d7b16fa32..000000000 --- a/src/mapping/map_management_old/map_management/map_management_node.py +++ /dev/null @@ -1,206 +0,0 @@ -''' -Package: map_management - File: map_management_node.py - Author: Will Heitman (w at heit dot mn) - -Node to subscribe to, provide, and handle map data, routes, -and related functions. -''' - -import math -from array import array as Array -from xml.etree import ElementTree as ET - -import numpy as np -import opendrivepy as odrpy -import pymap3d as pm -import rclpy -import ros2_numpy as rnp -from carla_msgs.msg import CarlaWorldInfo -from geometry_msgs.msg import Point, Pose, Quaternion, TransformStamped -from nav_msgs.msg import MapMetaData, OccupancyGrid, Odometry -from opendrivepy.map import Map -from rclpy.node import Node, QoSProfile -from rclpy.qos import DurabilityPolicy -from rosgraph_msgs.msg import Clock -from sensor_msgs.msg import NavSatFix, PointCloud2 -from std_msgs.msg import ColorRGBA, String -from visualization_msgs.msg import Marker - - -class MapManagementNode(Node): - - def __init__(self): - super().__init__('map_management') - self.odr_map: Map = None - self.road_grid = None - - self.map_string_sub = self.create_subscription( - String, '/carla/map', self.map_string_cb, 10 - ) - - self.gnss_sub = self.create_subscription( - NavSatFix, '/carla/hero/gnss', self.gnss_cb, 10 - ) - - self.world_info_sub = self.create_subscription( - CarlaWorldInfo, '/carla/world_info', self.world_info_cb, 10 - ) - - self.world_info_pub = self.create_publisher( - CarlaWorldInfo, '/carla/world_info', 10 - ) - - self.world_info_repub_timer = self.create_timer( - 0.5, self.repub_world_info) - - self.odom_pub = self.create_publisher( - Odometry, '/odometry/gnss_raw', 10 - ) - - self.odom_raw_pub = self.create_publisher( - Odometry, '/odometry_raw', 10 - ) - - self.clock_sub = self.create_subscription( - Clock, '/clock', self.clock_cb, 10 - ) - - self.grid_pub = self.create_publisher( - OccupancyGrid, '/grid/drivable', qos_profile=QoSProfile( - depth=10, durability=DurabilityPolicy.TRANSIENT_LOCAL - ) - ) - - self.grid_bounds_pub = self.create_publisher( - Marker, '/grid/bounds', 10) - - self.map_string = "" - - self.grid_pub_timer = self.create_timer(1, self.publish_map_grid) - - self.get_logger().info("Waiting for map data...") - self.map = None - self.clock = Clock() - self.world_info = CarlaWorldInfo() - - def publish_map_grid(self): - if (self.road_grid is None): - return - - self.road_grid.header.stamp = self.clock.clock - self.grid_pub.publish(self.road_grid) - - marker = Marker() - marker.action = Marker.ADD - marker.color.r = 1.0 - marker.color.a = 1.0 - marker.frame_locked = True - marker.header.frame_id = 'map' - marker.header.stamp = self.clock.clock - marker.id = 1 - marker.ns = 'grid' - marker.pose.position.x = self.odr_map.header.x_0 - marker.pose.position.y = self.odr_map.header.y_0 - marker.scale.x = 20.0 - marker.scale.y = 10.0 - marker.scale.z = 10.0 - marker.type = Marker.ARROW - - self.grid_bounds_pub.publish(marker) - - def clock_cb(self, msg: Clock): - if self.map_string == "": - with open('/navigator/lb_map.xml', 'r') as f: - self.map_string = f.read() - map_msg = String() - map_msg.data = self.map_string - self.clock = msg - self.map_string_cb(map_msg) - - def map_string_cb(self, msg: String): - self.get_logger().info("Received map. Processing now...") - map_string: str = msg.data - - grid_resolution = 0.4 - self.odr_map: Map = Map(map_string, grid_resolution=grid_resolution) - - road_grid_arr: np.array = self.odr_map.road_grid - road_grid_msg = OccupancyGrid() - road_grid_msg.data = Array('b', road_grid_arr.ravel().astype(np.int8)) - - meta = MapMetaData() - meta.height = road_grid_arr.shape[0] - meta.width = road_grid_arr.shape[1] - meta.map_load_time = self.clock.clock - meta.resolution = grid_resolution - - origin = Pose() - origin.position.x = self.odr_map.header.west_bound - origin.position.y = self.odr_map.header.south_bound - # origin.orientation.w = math.cos(-1*math.pi / 4) - # origin.orientation.z = math.sin(-1*math.pi / 4) - meta.origin = origin - - print( - f"Grid origin: ({origin.position.x},{origin.position.y},{origin.position.z}) @ {math.acos(origin.orientation.z)*2}") - - road_grid_msg.info = meta - road_grid_msg.header.frame_id = 'map' - road_grid_msg.header.stamp = self.clock.clock - - if self.road_grid is None: - self.get_logger().info("Setting road grid") - self.road_grid = road_grid_msg - - def gnss_cb(self, msg: NavSatFix): - if self.odr_map is None: - return - enu_xyz = pm.geodetic2enu( - msg.latitude, - msg.longitude, - msg.altitude, - self.odr_map.header.lat_0, - self.odr_map.header.lon_0, - 0.0 - ) - odom_msg = Odometry() - - # The odometry is for the current time-- right now - odom_msg.header.stamp = self.clock.clock - - # The odometry is the car's location on the map, - # so the child frame is "base_link" - odom_msg.header.frame_id = 'map' - odom_msg.child_frame_id = 'base_link' - pos = Point() - - pos.x = enu_xyz[0] - pos.y = enu_xyz[1] - pos.z = enu_xyz[2] - odom_msg.pose.pose.position = pos - self.odom_pub.publish(odom_msg) - - def world_info_cb(self, msg: CarlaWorldInfo): - self.world_info = msg - - def repub_world_info(self): - self.world_info_pub.publish(self.world_info) - - -def main(args=None): - rclpy.init(args=args) - - lidar_processor = MapManagementNode() - - rclpy.spin(lidar_processor) - - # Destroy the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - lidar_processor.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() diff --git a/src/mapping/map_management_old/setup.cfg b/src/mapping/map_management_old/setup.cfg deleted file mode 100755 index dc01f99e7..000000000 --- a/src/mapping/map_management_old/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[develop] -script-dir=$base/lib/map_management -[install] -install-scripts=$base/lib/map_management diff --git a/src/mapping/map_publishers/CMakeLists.txt b/src/mapping/map_publishers/CMakeLists.txt deleted file mode 100755 index eb0d90a7c..000000000 --- a/src/mapping/map_publishers/CMakeLists.txt +++ /dev/null @@ -1,91 +0,0 @@ -cmake_minimum_required(VERSION 3.5) -project(map_publishers) - -# Default to C99 -if(NOT CMAKE_C_STANDARD) - set(CMAKE_C_STANDARD 99) -endif() - -# Default to C++14 -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 14) -endif() - -if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wall -Wextra -Wpedantic) -endif() - -# find dependencies -find_package(ament_cmake_auto REQUIRED) -find_package(geometry_msgs REQUIRED) -find_package(lanelet2_core REQUIRED) -find_package(lanelet2_io REQUIRED) -find_package(lanelet2_projection REQUIRED) -find_package(nav_msgs REQUIRED) -find_package(PCL REQUIRED) -find_package(pcl_conversions REQUIRED) -find_package(sensor_msgs REQUIRED) -find_package(std_msgs REQUIRED) -find_package(tf2_ros REQUIRED) -find_package(visualization_msgs REQUIRED) - - -find_package(ament_cmake_auto REQUIRED) -ament_auto_find_build_dependencies() - -ament_auto_add_library(polypartition STATIC - lib/polypartition.cpp) -target_include_directories(polypartition PUBLIC lib) - -# uncomment the following section in order to fill in -# further dependencies manually. -# find_package( REQUIRED) - -add_executable(pcd_loader src/PCDLoader.cpp) -add_executable(lanelet_loader src/LaneletLoader.cpp) -target_include_directories(pcd_loader PUBLIC - $ - $) - -ament_target_dependencies( - lanelet_loader - geometry_msgs - rclcpp - lanelet2_core - lanelet2_io - lanelet2_projection - std_msgs - visualization_msgs - ) -ament_target_dependencies( - pcd_loader - geometry_msgs - nav_msgs - PCL - pcl_conversions - rclcpp - sensor_msgs - tf2_ros - ) - -include_directories(${PCL_INCLUDE_DIRS}) -link_directories(${PCL_LIBRARY_DIRS}) -add_definitions(${PCL_DEFINITIONS}) - -target_link_libraries (pcd_loader ${PCL_LIBRARIES}) -target_link_libraries(lanelet_loader polypartition) -install(TARGETS pcd_loader lanelet_loader - DESTINATION lib/${PROJECT_NAME}) - -if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - # the following line skips the linter which checks for copyrights - # uncomment the line when a copyright and license is not present in all source files - #set(ament_cmake_copyright_FOUND TRUE) - # the following line skips cpplint (only works in a git repo) - # uncomment the line when this package is not in a git repo - #set(ament_cmake_cpplint_FOUND TRUE) - ament_lint_auto_find_test_dependencies() -endif() - -ament_package() diff --git a/src/mapping/map_publishers/lib/polypartition.cpp b/src/mapping/map_publishers/lib/polypartition.cpp deleted file mode 100755 index 84aaf5b3e..000000000 --- a/src/mapping/map_publishers/lib/polypartition.cpp +++ /dev/null @@ -1,1851 +0,0 @@ -/*************************************************************************/ -/* Copyright (c) 2011-2021 Ivan Fratric and contributors. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "polypartition.h" - -#include -#include -#include -#include - -TPPLPoly::TPPLPoly() { - hole = false; - numpoints = 0; - points = NULL; -} - -TPPLPoly::~TPPLPoly() { - if (points) { - delete[] points; - } -} - -void TPPLPoly::Clear() { - if (points) { - delete[] points; - } - hole = false; - numpoints = 0; - points = NULL; -} - -void TPPLPoly::Init(long numpoints) { - Clear(); - this->numpoints = numpoints; - points = new TPPLPoint[numpoints]; -} - -void TPPLPoly::Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) { - Init(3); - points[0] = p1; - points[1] = p2; - points[2] = p3; -} - -TPPLPoly::TPPLPoly(const TPPLPoly &src) : - TPPLPoly() { - hole = src.hole; - numpoints = src.numpoints; - - if (numpoints > 0) { - points = new TPPLPoint[numpoints]; - memcpy(points, src.points, numpoints * sizeof(TPPLPoint)); - } -} - -TPPLPoly &TPPLPoly::operator=(const TPPLPoly &src) { - Clear(); - hole = src.hole; - numpoints = src.numpoints; - - if (numpoints > 0) { - points = new TPPLPoint[numpoints]; - memcpy(points, src.points, numpoints * sizeof(TPPLPoint)); - } - - return *this; -} - -TPPLOrientation TPPLPoly::GetOrientation() const { - long i1, i2; - tppl_float area = 0; - for (i1 = 0; i1 < numpoints; i1++) { - i2 = i1 + 1; - if (i2 == numpoints) { - i2 = 0; - } - area += points[i1].x * points[i2].y - points[i1].y * points[i2].x; - } - if (area > 0) { - return TPPL_ORIENTATION_CCW; - } - if (area < 0) { - return TPPL_ORIENTATION_CW; - } - return TPPL_ORIENTATION_NONE; -} - -void TPPLPoly::SetOrientation(TPPLOrientation orientation) { - TPPLOrientation polyorientation = GetOrientation(); - if (polyorientation != TPPL_ORIENTATION_NONE && polyorientation != orientation) { - Invert(); - } -} - -void TPPLPoly::Invert() { - std::reverse(points, points + numpoints); -} - -TPPLPartition::PartitionVertex::PartitionVertex() : - previous(NULL), next(NULL) { -} - -TPPLPoint TPPLPartition::Normalize(const TPPLPoint &p) { - TPPLPoint r; - tppl_float n = sqrt(p.x * p.x + p.y * p.y); - if (n != 0) { - r = p / n; - } else { - r.x = 0; - r.y = 0; - } - return r; -} - -tppl_float TPPLPartition::Distance(const TPPLPoint &p1, const TPPLPoint &p2) { - tppl_float dx, dy; - dx = p2.x - p1.x; - dy = p2.y - p1.y; - return (sqrt(dx * dx + dy * dy)); -} - -// Checks if two lines intersect. -int TPPLPartition::Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22) { - if ((p11.x == p21.x) && (p11.y == p21.y)) { - return 0; - } - if ((p11.x == p22.x) && (p11.y == p22.y)) { - return 0; - } - if ((p12.x == p21.x) && (p12.y == p21.y)) { - return 0; - } - if ((p12.x == p22.x) && (p12.y == p22.y)) { - return 0; - } - - TPPLPoint v1ort, v2ort, v; - tppl_float dot11, dot12, dot21, dot22; - - v1ort.x = p12.y - p11.y; - v1ort.y = p11.x - p12.x; - - v2ort.x = p22.y - p21.y; - v2ort.y = p21.x - p22.x; - - v = p21 - p11; - dot21 = v.x * v1ort.x + v.y * v1ort.y; - v = p22 - p11; - dot22 = v.x * v1ort.x + v.y * v1ort.y; - - v = p11 - p21; - dot11 = v.x * v2ort.x + v.y * v2ort.y; - v = p12 - p21; - dot12 = v.x * v2ort.x + v.y * v2ort.y; - - if (dot11 * dot12 > 0) { - return 0; - } - if (dot21 * dot22 > 0) { - return 0; - } - - return 1; -} - -// Removes holes from inpolys by merging them with non-holes. -int TPPLPartition::RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys) { - TPPLPolyList polys; - TPPLPolyList::iterator holeiter, polyiter, iter, iter2; - long i, i2, holepointindex, polypointindex; - TPPLPoint holepoint, polypoint, bestpolypoint; - TPPLPoint linep1, linep2; - TPPLPoint v1, v2; - TPPLPoly newpoly; - bool hasholes; - bool pointvisible; - bool pointfound; - - // Check for the trivial case of no holes. - hasholes = false; - for (iter = inpolys->begin(); iter != inpolys->end(); iter++) { - if (iter->IsHole()) { - hasholes = true; - break; - } - } - if (!hasholes) { - for (iter = inpolys->begin(); iter != inpolys->end(); iter++) { - outpolys->push_back(*iter); - } - return 1; - } - - polys = *inpolys; - - while (1) { - // Find the hole point with the largest x. - hasholes = false; - for (iter = polys.begin(); iter != polys.end(); iter++) { - if (!iter->IsHole()) { - continue; - } - - if (!hasholes) { - hasholes = true; - holeiter = iter; - holepointindex = 0; - } - - for (i = 0; i < iter->GetNumPoints(); i++) { - if (iter->GetPoint(i).x > holeiter->GetPoint(holepointindex).x) { - holeiter = iter; - holepointindex = i; - } - } - } - if (!hasholes) { - break; - } - holepoint = holeiter->GetPoint(holepointindex); - - pointfound = false; - for (iter = polys.begin(); iter != polys.end(); iter++) { - if (iter->IsHole()) { - continue; - } - for (i = 0; i < iter->GetNumPoints(); i++) { - if (iter->GetPoint(i).x <= holepoint.x) { - continue; - } - if (!InCone(iter->GetPoint((i + iter->GetNumPoints() - 1) % (iter->GetNumPoints())), - iter->GetPoint(i), - iter->GetPoint((i + 1) % (iter->GetNumPoints())), - holepoint)) { - continue; - } - polypoint = iter->GetPoint(i); - if (pointfound) { - v1 = Normalize(polypoint - holepoint); - v2 = Normalize(bestpolypoint - holepoint); - if (v2.x > v1.x) { - continue; - } - } - pointvisible = true; - for (iter2 = polys.begin(); iter2 != polys.end(); iter2++) { - if (iter2->IsHole()) { - continue; - } - for (i2 = 0; i2 < iter2->GetNumPoints(); i2++) { - linep1 = iter2->GetPoint(i2); - linep2 = iter2->GetPoint((i2 + 1) % (iter2->GetNumPoints())); - if (Intersects(holepoint, polypoint, linep1, linep2)) { - pointvisible = false; - break; - } - } - if (!pointvisible) { - break; - } - } - if (pointvisible) { - pointfound = true; - bestpolypoint = polypoint; - polyiter = iter; - polypointindex = i; - } - } - } - - if (!pointfound) { - return 0; - } - - newpoly.Init(holeiter->GetNumPoints() + polyiter->GetNumPoints() + 2); - i2 = 0; - for (i = 0; i <= polypointindex; i++) { - newpoly[i2] = polyiter->GetPoint(i); - i2++; - } - for (i = 0; i <= holeiter->GetNumPoints(); i++) { - newpoly[i2] = holeiter->GetPoint((i + holepointindex) % holeiter->GetNumPoints()); - i2++; - } - for (i = polypointindex; i < polyiter->GetNumPoints(); i++) { - newpoly[i2] = polyiter->GetPoint(i); - i2++; - } - - polys.erase(holeiter); - polys.erase(polyiter); - polys.push_back(newpoly); - } - - for (iter = polys.begin(); iter != polys.end(); iter++) { - outpolys->push_back(*iter); - } - - return 1; -} - -bool TPPLPartition::IsConvex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) { - tppl_float tmp; - tmp = (p3.y - p1.y) * (p2.x - p1.x) - (p3.x - p1.x) * (p2.y - p1.y); - if (tmp > 0) { - return 1; - } else { - return 0; - } -} - -bool TPPLPartition::IsReflex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3) { - tppl_float tmp; - tmp = (p3.y - p1.y) * (p2.x - p1.x) - (p3.x - p1.x) * (p2.y - p1.y); - if (tmp < 0) { - return 1; - } else { - return 0; - } -} - -bool TPPLPartition::IsInside(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p) { - if (IsConvex(p1, p, p2)) { - return false; - } - if (IsConvex(p2, p, p3)) { - return false; - } - if (IsConvex(p3, p, p1)) { - return false; - } - return true; -} - -bool TPPLPartition::InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p) { - bool convex; - - convex = IsConvex(p1, p2, p3); - - if (convex) { - if (!IsConvex(p1, p2, p)) { - return false; - } - if (!IsConvex(p2, p3, p)) { - return false; - } - return true; - } else { - if (IsConvex(p1, p2, p)) { - return true; - } - if (IsConvex(p2, p3, p)) { - return true; - } - return false; - } -} - -bool TPPLPartition::InCone(PartitionVertex *v, TPPLPoint &p) { - TPPLPoint p1, p2, p3; - - p1 = v->previous->p; - p2 = v->p; - p3 = v->next->p; - - return InCone(p1, p2, p3, p); -} - -void TPPLPartition::UpdateVertexReflexity(PartitionVertex *v) { - PartitionVertex *v1 = NULL, *v3 = NULL; - v1 = v->previous; - v3 = v->next; - v->isConvex = !IsReflex(v1->p, v->p, v3->p); -} - -void TPPLPartition::UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices) { - long i; - PartitionVertex *v1 = NULL, *v3 = NULL; - TPPLPoint vec1, vec3; - - v1 = v->previous; - v3 = v->next; - - v->isConvex = IsConvex(v1->p, v->p, v3->p); - - vec1 = Normalize(v1->p - v->p); - vec3 = Normalize(v3->p - v->p); - v->angle = vec1.x * vec3.x + vec1.y * vec3.y; - - if (v->isConvex) { - v->isEar = true; - for (i = 0; i < numvertices; i++) { - if ((vertices[i].p.x == v->p.x) && (vertices[i].p.y == v->p.y)) { - continue; - } - if ((vertices[i].p.x == v1->p.x) && (vertices[i].p.y == v1->p.y)) { - continue; - } - if ((vertices[i].p.x == v3->p.x) && (vertices[i].p.y == v3->p.y)) { - continue; - } - if (IsInside(v1->p, v->p, v3->p, vertices[i].p)) { - v->isEar = false; - break; - } - } - } else { - v->isEar = false; - } -} - -// Triangulation by ear removal. -int TPPLPartition::Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles) { - if (!poly->Valid()) { - return 0; - } - - long numvertices; - PartitionVertex *vertices = NULL; - PartitionVertex *ear = NULL; - TPPLPoly triangle; - long i, j; - bool earfound; - - if (poly->GetNumPoints() < 3) { - return 0; - } - if (poly->GetNumPoints() == 3) { - triangles->push_back(*poly); - return 1; - } - - numvertices = poly->GetNumPoints(); - - vertices = new PartitionVertex[numvertices]; - for (i = 0; i < numvertices; i++) { - vertices[i].isActive = true; - vertices[i].p = poly->GetPoint(i); - if (i == (numvertices - 1)) { - vertices[i].next = &(vertices[0]); - } else { - vertices[i].next = &(vertices[i + 1]); - } - if (i == 0) { - vertices[i].previous = &(vertices[numvertices - 1]); - } else { - vertices[i].previous = &(vertices[i - 1]); - } - } - for (i = 0; i < numvertices; i++) { - UpdateVertex(&vertices[i], vertices, numvertices); - } - - for (i = 0; i < numvertices - 3; i++) { - earfound = false; - // Find the most extruded ear. - for (j = 0; j < numvertices; j++) { - if (!vertices[j].isActive) { - continue; - } - if (!vertices[j].isEar) { - continue; - } - if (!earfound) { - earfound = true; - ear = &(vertices[j]); - } else { - if (vertices[j].angle > ear->angle) { - ear = &(vertices[j]); - } - } - } - if (!earfound) { - delete[] vertices; - return 0; - } - - triangle.Triangle(ear->previous->p, ear->p, ear->next->p); - triangles->push_back(triangle); - - ear->isActive = false; - ear->previous->next = ear->next; - ear->next->previous = ear->previous; - - if (i == numvertices - 4) { - break; - } - - UpdateVertex(ear->previous, vertices, numvertices); - UpdateVertex(ear->next, vertices, numvertices); - } - for (i = 0; i < numvertices; i++) { - if (vertices[i].isActive) { - triangle.Triangle(vertices[i].previous->p, vertices[i].p, vertices[i].next->p); - triangles->push_back(triangle); - break; - } - } - - delete[] vertices; - - return 1; -} - -int TPPLPartition::Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles) { - TPPLPolyList outpolys; - TPPLPolyList::iterator iter; - - if (!RemoveHoles(inpolys, &outpolys)) { - return 0; - } - for (iter = outpolys.begin(); iter != outpolys.end(); iter++) { - if (!Triangulate_EC(&(*iter), triangles)) { - return 0; - } - } - return 1; -} - -int TPPLPartition::ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts) { - if (!poly->Valid()) { - return 0; - } - - TPPLPolyList triangles; - TPPLPolyList::iterator iter1, iter2; - TPPLPoly *poly1 = NULL, *poly2 = NULL; - TPPLPoly newpoly; - TPPLPoint d1, d2, p1, p2, p3; - long i11, i12, i21, i22, i13, i23, j, k; - bool isdiagonal; - long numreflex; - - // Check if the poly is already convex. - numreflex = 0; - for (i11 = 0; i11 < poly->GetNumPoints(); i11++) { - if (i11 == 0) { - i12 = poly->GetNumPoints() - 1; - } else { - i12 = i11 - 1; - } - if (i11 == (poly->GetNumPoints() - 1)) { - i13 = 0; - } else { - i13 = i11 + 1; - } - if (IsReflex(poly->GetPoint(i12), poly->GetPoint(i11), poly->GetPoint(i13))) { - numreflex = 1; - break; - } - } - if (numreflex == 0) { - parts->push_back(*poly); - return 1; - } - - if (!Triangulate_EC(poly, &triangles)) { - return 0; - } - - for (iter1 = triangles.begin(); iter1 != triangles.end(); iter1++) { - poly1 = &(*iter1); - for (i11 = 0; i11 < poly1->GetNumPoints(); i11++) { - d1 = poly1->GetPoint(i11); - i12 = (i11 + 1) % (poly1->GetNumPoints()); - d2 = poly1->GetPoint(i12); - - isdiagonal = false; - for (iter2 = iter1; iter2 != triangles.end(); iter2++) { - if (iter1 == iter2) { - continue; - } - poly2 = &(*iter2); - - for (i21 = 0; i21 < poly2->GetNumPoints(); i21++) { - if ((d2.x != poly2->GetPoint(i21).x) || (d2.y != poly2->GetPoint(i21).y)) { - continue; - } - i22 = (i21 + 1) % (poly2->GetNumPoints()); - if ((d1.x != poly2->GetPoint(i22).x) || (d1.y != poly2->GetPoint(i22).y)) { - continue; - } - isdiagonal = true; - break; - } - if (isdiagonal) { - break; - } - } - - if (!isdiagonal) { - continue; - } - - p2 = poly1->GetPoint(i11); - if (i11 == 0) { - i13 = poly1->GetNumPoints() - 1; - } else { - i13 = i11 - 1; - } - p1 = poly1->GetPoint(i13); - if (i22 == (poly2->GetNumPoints() - 1)) { - i23 = 0; - } else { - i23 = i22 + 1; - } - p3 = poly2->GetPoint(i23); - - if (!IsConvex(p1, p2, p3)) { - continue; - } - - p2 = poly1->GetPoint(i12); - if (i12 == (poly1->GetNumPoints() - 1)) { - i13 = 0; - } else { - i13 = i12 + 1; - } - p3 = poly1->GetPoint(i13); - if (i21 == 0) { - i23 = poly2->GetNumPoints() - 1; - } else { - i23 = i21 - 1; - } - p1 = poly2->GetPoint(i23); - - if (!IsConvex(p1, p2, p3)) { - continue; - } - - newpoly.Init(poly1->GetNumPoints() + poly2->GetNumPoints() - 2); - k = 0; - for (j = i12; j != i11; j = (j + 1) % (poly1->GetNumPoints())) { - newpoly[k] = poly1->GetPoint(j); - k++; - } - for (j = i22; j != i21; j = (j + 1) % (poly2->GetNumPoints())) { - newpoly[k] = poly2->GetPoint(j); - k++; - } - - triangles.erase(iter2); - *iter1 = newpoly; - poly1 = &(*iter1); - i11 = -1; - - continue; - } - } - - for (iter1 = triangles.begin(); iter1 != triangles.end(); iter1++) { - parts->push_back(*iter1); - } - - return 1; -} - -int TPPLPartition::ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts) { - TPPLPolyList outpolys; - TPPLPolyList::iterator iter; - - if (!RemoveHoles(inpolys, &outpolys)) { - return 0; - } - for (iter = outpolys.begin(); iter != outpolys.end(); iter++) { - if (!ConvexPartition_HM(&(*iter), parts)) { - return 0; - } - } - return 1; -} - -// Minimum-weight polygon triangulation by dynamic programming. -// Time complexity: O(n^3) -// Space complexity: O(n^2) -int TPPLPartition::Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles) { - if (!poly->Valid()) { - return 0; - } - - long i, j, k, gap, n; - DPState **dpstates = NULL; - TPPLPoint p1, p2, p3, p4; - long bestvertex; - tppl_float weight, minweight, d1, d2; - Diagonal diagonal, newdiagonal; - DiagonalList diagonals; - TPPLPoly triangle; - int ret = 1; - - n = poly->GetNumPoints(); - dpstates = new DPState *[n]; - for (i = 1; i < n; i++) { - dpstates[i] = new DPState[i]; - } - - // Initialize states and visibility. - for (i = 0; i < (n - 1); i++) { - p1 = poly->GetPoint(i); - for (j = i + 1; j < n; j++) { - dpstates[j][i].visible = true; - dpstates[j][i].weight = 0; - dpstates[j][i].bestvertex = -1; - if (j != (i + 1)) { - p2 = poly->GetPoint(j); - - // Visibility check. - if (i == 0) { - p3 = poly->GetPoint(n - 1); - } else { - p3 = poly->GetPoint(i - 1); - } - if (i == (n - 1)) { - p4 = poly->GetPoint(0); - } else { - p4 = poly->GetPoint(i + 1); - } - if (!InCone(p3, p1, p4, p2)) { - dpstates[j][i].visible = false; - continue; - } - - if (j == 0) { - p3 = poly->GetPoint(n - 1); - } else { - p3 = poly->GetPoint(j - 1); - } - if (j == (n - 1)) { - p4 = poly->GetPoint(0); - } else { - p4 = poly->GetPoint(j + 1); - } - if (!InCone(p3, p2, p4, p1)) { - dpstates[j][i].visible = false; - continue; - } - - for (k = 0; k < n; k++) { - p3 = poly->GetPoint(k); - if (k == (n - 1)) { - p4 = poly->GetPoint(0); - } else { - p4 = poly->GetPoint(k + 1); - } - if (Intersects(p1, p2, p3, p4)) { - dpstates[j][i].visible = false; - break; - } - } - } - } - } - dpstates[n - 1][0].visible = true; - dpstates[n - 1][0].weight = 0; - dpstates[n - 1][0].bestvertex = -1; - - for (gap = 2; gap < n; gap++) { - for (i = 0; i < (n - gap); i++) { - j = i + gap; - if (!dpstates[j][i].visible) { - continue; - } - bestvertex = -1; - for (k = (i + 1); k < j; k++) { - if (!dpstates[k][i].visible) { - continue; - } - if (!dpstates[j][k].visible) { - continue; - } - - if (k <= (i + 1)) { - d1 = 0; - } else { - d1 = Distance(poly->GetPoint(i), poly->GetPoint(k)); - } - if (j <= (k + 1)) { - d2 = 0; - } else { - d2 = Distance(poly->GetPoint(k), poly->GetPoint(j)); - } - - weight = dpstates[k][i].weight + dpstates[j][k].weight + d1 + d2; - - if ((bestvertex == -1) || (weight < minweight)) { - bestvertex = k; - minweight = weight; - } - } - if (bestvertex == -1) { - for (i = 1; i < n; i++) { - delete[] dpstates[i]; - } - delete[] dpstates; - - return 0; - } - - dpstates[j][i].bestvertex = bestvertex; - dpstates[j][i].weight = minweight; - } - } - - newdiagonal.index1 = 0; - newdiagonal.index2 = n - 1; - diagonals.push_back(newdiagonal); - while (!diagonals.empty()) { - diagonal = *(diagonals.begin()); - diagonals.pop_front(); - bestvertex = dpstates[diagonal.index2][diagonal.index1].bestvertex; - if (bestvertex == -1) { - ret = 0; - break; - } - triangle.Triangle(poly->GetPoint(diagonal.index1), poly->GetPoint(bestvertex), poly->GetPoint(diagonal.index2)); - triangles->push_back(triangle); - if (bestvertex > (diagonal.index1 + 1)) { - newdiagonal.index1 = diagonal.index1; - newdiagonal.index2 = bestvertex; - diagonals.push_back(newdiagonal); - } - if (diagonal.index2 > (bestvertex + 1)) { - newdiagonal.index1 = bestvertex; - newdiagonal.index2 = diagonal.index2; - diagonals.push_back(newdiagonal); - } - } - - for (i = 1; i < n; i++) { - delete[] dpstates[i]; - } - delete[] dpstates; - - return ret; -} - -void TPPLPartition::UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates) { - Diagonal newdiagonal; - DiagonalList *pairs = NULL; - long w2; - - w2 = dpstates[a][b].weight; - if (w > w2) { - return; - } - - pairs = &(dpstates[a][b].pairs); - newdiagonal.index1 = i; - newdiagonal.index2 = j; - - if (w < w2) { - pairs->clear(); - pairs->push_front(newdiagonal); - dpstates[a][b].weight = w; - } else { - if ((!pairs->empty()) && (i <= pairs->begin()->index1)) { - return; - } - while ((!pairs->empty()) && (pairs->begin()->index2 >= j)) { - pairs->pop_front(); - } - pairs->push_front(newdiagonal); - } -} - -void TPPLPartition::TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { - DiagonalList *pairs = NULL; - DiagonalList::iterator iter, lastiter; - long top; - long w; - - if (!dpstates[i][j].visible) { - return; - } - top = j; - w = dpstates[i][j].weight; - if (k - j > 1) { - if (!dpstates[j][k].visible) { - return; - } - w += dpstates[j][k].weight + 1; - } - if (j - i > 1) { - pairs = &(dpstates[i][j].pairs); - iter = pairs->end(); - lastiter = pairs->end(); - while (iter != pairs->begin()) { - iter--; - if (!IsReflex(vertices[iter->index2].p, vertices[j].p, vertices[k].p)) { - lastiter = iter; - } else { - break; - } - } - if (lastiter == pairs->end()) { - w++; - } else { - if (IsReflex(vertices[k].p, vertices[i].p, vertices[lastiter->index1].p)) { - w++; - } else { - top = lastiter->index1; - } - } - } - UpdateState(i, k, w, top, j, dpstates); -} - -void TPPLPartition::TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates) { - DiagonalList *pairs = NULL; - DiagonalList::iterator iter, lastiter; - long top; - long w; - - if (!dpstates[j][k].visible) { - return; - } - top = j; - w = dpstates[j][k].weight; - - if (j - i > 1) { - if (!dpstates[i][j].visible) { - return; - } - w += dpstates[i][j].weight + 1; - } - if (k - j > 1) { - pairs = &(dpstates[j][k].pairs); - - iter = pairs->begin(); - if ((!pairs->empty()) && (!IsReflex(vertices[i].p, vertices[j].p, vertices[iter->index1].p))) { - lastiter = iter; - while (iter != pairs->end()) { - if (!IsReflex(vertices[i].p, vertices[j].p, vertices[iter->index1].p)) { - lastiter = iter; - iter++; - } else { - break; - } - } - if (IsReflex(vertices[lastiter->index2].p, vertices[k].p, vertices[i].p)) { - w++; - } else { - top = lastiter->index2; - } - } else { - w++; - } - } - UpdateState(i, k, w, j, top, dpstates); -} - -int TPPLPartition::ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts) { - if (!poly->Valid()) { - return 0; - } - - TPPLPoint p1, p2, p3, p4; - PartitionVertex *vertices = NULL; - DPState2 **dpstates = NULL; - long i, j, k, n, gap; - DiagonalList diagonals, diagonals2; - Diagonal diagonal, newdiagonal; - DiagonalList *pairs = NULL, *pairs2 = NULL; - DiagonalList::iterator iter, iter2; - int ret; - TPPLPoly newpoly; - std::vector indices; - std::vector::iterator iiter; - bool ijreal, jkreal; - - n = poly->GetNumPoints(); - vertices = new PartitionVertex[n]; - - dpstates = new DPState2 *[n]; - for (i = 0; i < n; i++) { - dpstates[i] = new DPState2[n]; - } - - // Initialize vertex information. - for (i = 0; i < n; i++) { - vertices[i].p = poly->GetPoint(i); - vertices[i].isActive = true; - if (i == 0) { - vertices[i].previous = &(vertices[n - 1]); - } else { - vertices[i].previous = &(vertices[i - 1]); - } - if (i == (poly->GetNumPoints() - 1)) { - vertices[i].next = &(vertices[0]); - } else { - vertices[i].next = &(vertices[i + 1]); - } - } - for (i = 1; i < n; i++) { - UpdateVertexReflexity(&(vertices[i])); - } - - // Initialize states and visibility. - for (i = 0; i < (n - 1); i++) { - p1 = poly->GetPoint(i); - for (j = i + 1; j < n; j++) { - dpstates[i][j].visible = true; - if (j == i + 1) { - dpstates[i][j].weight = 0; - } else { - dpstates[i][j].weight = 2147483647; - } - if (j != (i + 1)) { - p2 = poly->GetPoint(j); - - // Visibility check. - if (!InCone(&vertices[i], p2)) { - dpstates[i][j].visible = false; - continue; - } - if (!InCone(&vertices[j], p1)) { - dpstates[i][j].visible = false; - continue; - } - - for (k = 0; k < n; k++) { - p3 = poly->GetPoint(k); - if (k == (n - 1)) { - p4 = poly->GetPoint(0); - } else { - p4 = poly->GetPoint(k + 1); - } - if (Intersects(p1, p2, p3, p4)) { - dpstates[i][j].visible = false; - break; - } - } - } - } - } - for (i = 0; i < (n - 2); i++) { - j = i + 2; - if (dpstates[i][j].visible) { - dpstates[i][j].weight = 0; - newdiagonal.index1 = i + 1; - newdiagonal.index2 = i + 1; - dpstates[i][j].pairs.push_back(newdiagonal); - } - } - - dpstates[0][n - 1].visible = true; - vertices[0].isConvex = false; // By convention. - - for (gap = 3; gap < n; gap++) { - for (i = 0; i < n - gap; i++) { - if (vertices[i].isConvex) { - continue; - } - k = i + gap; - if (dpstates[i][k].visible) { - if (!vertices[k].isConvex) { - for (j = i + 1; j < k; j++) { - TypeA(i, j, k, vertices, dpstates); - } - } else { - for (j = i + 1; j < (k - 1); j++) { - if (vertices[j].isConvex) { - continue; - } - TypeA(i, j, k, vertices, dpstates); - } - TypeA(i, k - 1, k, vertices, dpstates); - } - } - } - for (k = gap; k < n; k++) { - if (vertices[k].isConvex) { - continue; - } - i = k - gap; - if ((vertices[i].isConvex) && (dpstates[i][k].visible)) { - TypeB(i, i + 1, k, vertices, dpstates); - for (j = i + 2; j < k; j++) { - if (vertices[j].isConvex) { - continue; - } - TypeB(i, j, k, vertices, dpstates); - } - } - } - } - - // Recover solution. - ret = 1; - newdiagonal.index1 = 0; - newdiagonal.index2 = n - 1; - diagonals.push_front(newdiagonal); - while (!diagonals.empty()) { - diagonal = *(diagonals.begin()); - diagonals.pop_front(); - if ((diagonal.index2 - diagonal.index1) <= 1) { - continue; - } - pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs); - if (pairs->empty()) { - ret = 0; - break; - } - if (!vertices[diagonal.index1].isConvex) { - iter = pairs->end(); - iter--; - j = iter->index2; - newdiagonal.index1 = j; - newdiagonal.index2 = diagonal.index2; - diagonals.push_front(newdiagonal); - if ((j - diagonal.index1) > 1) { - if (iter->index1 != iter->index2) { - pairs2 = &(dpstates[diagonal.index1][j].pairs); - while (1) { - if (pairs2->empty()) { - ret = 0; - break; - } - iter2 = pairs2->end(); - iter2--; - if (iter->index1 != iter2->index1) { - pairs2->pop_back(); - } else { - break; - } - } - if (ret == 0) { - break; - } - } - newdiagonal.index1 = diagonal.index1; - newdiagonal.index2 = j; - diagonals.push_front(newdiagonal); - } - } else { - iter = pairs->begin(); - j = iter->index1; - newdiagonal.index1 = diagonal.index1; - newdiagonal.index2 = j; - diagonals.push_front(newdiagonal); - if ((diagonal.index2 - j) > 1) { - if (iter->index1 != iter->index2) { - pairs2 = &(dpstates[j][diagonal.index2].pairs); - while (1) { - if (pairs2->empty()) { - ret = 0; - break; - } - iter2 = pairs2->begin(); - if (iter->index2 != iter2->index2) { - pairs2->pop_front(); - } else { - break; - } - } - if (ret == 0) { - break; - } - } - newdiagonal.index1 = j; - newdiagonal.index2 = diagonal.index2; - diagonals.push_front(newdiagonal); - } - } - } - - if (ret == 0) { - for (i = 0; i < n; i++) { - delete[] dpstates[i]; - } - delete[] dpstates; - delete[] vertices; - - return ret; - } - - newdiagonal.index1 = 0; - newdiagonal.index2 = n - 1; - diagonals.push_front(newdiagonal); - while (!diagonals.empty()) { - diagonal = *(diagonals.begin()); - diagonals.pop_front(); - if ((diagonal.index2 - diagonal.index1) <= 1) { - continue; - } - - indices.clear(); - diagonals2.clear(); - indices.push_back(diagonal.index1); - indices.push_back(diagonal.index2); - diagonals2.push_front(diagonal); - - while (!diagonals2.empty()) { - diagonal = *(diagonals2.begin()); - diagonals2.pop_front(); - if ((diagonal.index2 - diagonal.index1) <= 1) { - continue; - } - ijreal = true; - jkreal = true; - pairs = &(dpstates[diagonal.index1][diagonal.index2].pairs); - if (!vertices[diagonal.index1].isConvex) { - iter = pairs->end(); - iter--; - j = iter->index2; - if (iter->index1 != iter->index2) { - ijreal = false; - } - } else { - iter = pairs->begin(); - j = iter->index1; - if (iter->index1 != iter->index2) { - jkreal = false; - } - } - - newdiagonal.index1 = diagonal.index1; - newdiagonal.index2 = j; - if (ijreal) { - diagonals.push_back(newdiagonal); - } else { - diagonals2.push_back(newdiagonal); - } - - newdiagonal.index1 = j; - newdiagonal.index2 = diagonal.index2; - if (jkreal) { - diagonals.push_back(newdiagonal); - } else { - diagonals2.push_back(newdiagonal); - } - - indices.push_back(j); - } - - std::sort(indices.begin(), indices.end()); - newpoly.Init((long)indices.size()); - k = 0; - for (iiter = indices.begin(); iiter != indices.end(); iiter++) { - newpoly[k] = vertices[*iiter].p; - k++; - } - parts->push_back(newpoly); - } - - for (i = 0; i < n; i++) { - delete[] dpstates[i]; - } - delete[] dpstates; - delete[] vertices; - - return ret; -} - -// Creates a monotone partition of a list of polygons that -// can contain holes. Triangulates a set of polygons by -// first partitioning them into monotone polygons. -// Time complexity: O(n*log(n)), n is the number of vertices. -// Space complexity: O(n) -// The algorithm used here is outlined in the book -// "Computational Geometry: Algorithms and Applications" -// by Mark de Berg, Otfried Cheong, Marc van Kreveld, and Mark Overmars. -int TPPLPartition::MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys) { - TPPLPolyList::iterator iter; - MonotoneVertex *vertices = NULL; - long i, numvertices, vindex, vindex2, newnumvertices, maxnumvertices; - long polystartindex, polyendindex; - TPPLPoly *poly = NULL; - MonotoneVertex *v = NULL, *v2 = NULL, *vprev = NULL, *vnext = NULL; - ScanLineEdge newedge; - bool error = false; - - numvertices = 0; - for (iter = inpolys->begin(); iter != inpolys->end(); iter++) { - if (!iter->Valid()) { - return 0; - } - numvertices += iter->GetNumPoints(); - } - - maxnumvertices = numvertices * 3; - vertices = new MonotoneVertex[maxnumvertices]; - newnumvertices = numvertices; - - polystartindex = 0; - for (iter = inpolys->begin(); iter != inpolys->end(); iter++) { - poly = &(*iter); - polyendindex = polystartindex + poly->GetNumPoints() - 1; - for (i = 0; i < poly->GetNumPoints(); i++) { - vertices[i + polystartindex].p = poly->GetPoint(i); - if (i == 0) { - vertices[i + polystartindex].previous = polyendindex; - } else { - vertices[i + polystartindex].previous = i + polystartindex - 1; - } - if (i == (poly->GetNumPoints() - 1)) { - vertices[i + polystartindex].next = polystartindex; - } else { - vertices[i + polystartindex].next = i + polystartindex + 1; - } - } - polystartindex = polyendindex + 1; - } - - // Construct the priority queue. - long *priority = new long[numvertices]; - for (i = 0; i < numvertices; i++) { - priority[i] = i; - } - std::sort(priority, &(priority[numvertices]), VertexSorter(vertices)); - - // Determine vertex types. - TPPLVertexType *vertextypes = new TPPLVertexType[maxnumvertices]; - for (i = 0; i < numvertices; i++) { - v = &(vertices[i]); - vprev = &(vertices[v->previous]); - vnext = &(vertices[v->next]); - - if (Below(vprev->p, v->p) && Below(vnext->p, v->p)) { - if (IsConvex(vnext->p, vprev->p, v->p)) { - vertextypes[i] = TPPL_VERTEXTYPE_START; - } else { - vertextypes[i] = TPPL_VERTEXTYPE_SPLIT; - } - } else if (Below(v->p, vprev->p) && Below(v->p, vnext->p)) { - if (IsConvex(vnext->p, vprev->p, v->p)) { - vertextypes[i] = TPPL_VERTEXTYPE_END; - } else { - vertextypes[i] = TPPL_VERTEXTYPE_MERGE; - } - } else { - vertextypes[i] = TPPL_VERTEXTYPE_REGULAR; - } - } - - // Helpers. - long *helpers = new long[maxnumvertices]; - - // Binary search tree that holds edges intersecting the scanline. - // Note that while set doesn't actually have to be implemented as - // a tree, complexity requirements for operations are the same as - // for the balanced binary search tree. - std::set edgeTree; - // Store iterators to the edge tree elements. - // This makes deleting existing edges much faster. - std::set::iterator *edgeTreeIterators, edgeIter; - edgeTreeIterators = new std::set::iterator[maxnumvertices]; - std::pair::iterator, bool> edgeTreeRet; - for (i = 0; i < numvertices; i++) { - edgeTreeIterators[i] = edgeTree.end(); - } - - // For each vertex. - for (i = 0; i < numvertices; i++) { - vindex = priority[i]; - v = &(vertices[vindex]); - vindex2 = vindex; - v2 = v; - - // Depending on the vertex type, do the appropriate action. - // Comments in the following sections are copied from - // "Computational Geometry: Algorithms and Applications". - // Notation: e_i = e subscript i, v_i = v subscript i, etc. - switch (vertextypes[vindex]) { - case TPPL_VERTEXTYPE_START: - // Insert e_i in T and set helper(e_i) to v_i. - newedge.p1 = v->p; - newedge.p2 = vertices[v->next].p; - newedge.index = vindex; - edgeTreeRet = edgeTree.insert(newedge); - edgeTreeIterators[vindex] = edgeTreeRet.first; - helpers[vindex] = vindex; - break; - - case TPPL_VERTEXTYPE_END: - if (edgeTreeIterators[v->previous] == edgeTree.end()) { - error = true; - break; - } - // If helper(e_i - 1) is a merge vertex - if (vertextypes[helpers[v->previous]] == TPPL_VERTEXTYPE_MERGE) { - // Insert the diagonal connecting vi to helper(e_i - 1) in D. - AddDiagonal(vertices, &newnumvertices, vindex, helpers[v->previous], - vertextypes, edgeTreeIterators, &edgeTree, helpers); - } - // Delete e_i - 1 from T - edgeTree.erase(edgeTreeIterators[v->previous]); - break; - - case TPPL_VERTEXTYPE_SPLIT: - // Search in T to find the edge e_j directly left of v_i. - newedge.p1 = v->p; - newedge.p2 = v->p; - edgeIter = edgeTree.lower_bound(newedge); - if (edgeIter == edgeTree.begin()) { - error = true; - break; - } - edgeIter--; - // Insert the diagonal connecting vi to helper(e_j) in D. - AddDiagonal(vertices, &newnumvertices, vindex, helpers[edgeIter->index], - vertextypes, edgeTreeIterators, &edgeTree, helpers); - vindex2 = newnumvertices - 2; - v2 = &(vertices[vindex2]); - // helper(e_j) in v_i. - helpers[edgeIter->index] = vindex; - // Insert e_i in T and set helper(e_i) to v_i. - newedge.p1 = v2->p; - newedge.p2 = vertices[v2->next].p; - newedge.index = vindex2; - edgeTreeRet = edgeTree.insert(newedge); - edgeTreeIterators[vindex2] = edgeTreeRet.first; - helpers[vindex2] = vindex2; - break; - - case TPPL_VERTEXTYPE_MERGE: - if (edgeTreeIterators[v->previous] == edgeTree.end()) { - error = true; - break; - } - // if helper(e_i - 1) is a merge vertex - if (vertextypes[helpers[v->previous]] == TPPL_VERTEXTYPE_MERGE) { - // Insert the diagonal connecting vi to helper(e_i - 1) in D. - AddDiagonal(vertices, &newnumvertices, vindex, helpers[v->previous], - vertextypes, edgeTreeIterators, &edgeTree, helpers); - vindex2 = newnumvertices - 2; - v2 = &(vertices[vindex2]); - } - // Delete e_i - 1 from T. - edgeTree.erase(edgeTreeIterators[v->previous]); - // Search in T to find the edge e_j directly left of v_i. - newedge.p1 = v->p; - newedge.p2 = v->p; - edgeIter = edgeTree.lower_bound(newedge); - if (edgeIter == edgeTree.begin()) { - error = true; - break; - } - edgeIter--; - // If helper(e_j) is a merge vertex. - if (vertextypes[helpers[edgeIter->index]] == TPPL_VERTEXTYPE_MERGE) { - // Insert the diagonal connecting v_i to helper(e_j) in D. - AddDiagonal(vertices, &newnumvertices, vindex2, helpers[edgeIter->index], - vertextypes, edgeTreeIterators, &edgeTree, helpers); - } - // helper(e_j) <- v_i - helpers[edgeIter->index] = vindex2; - break; - - case TPPL_VERTEXTYPE_REGULAR: - // If the interior of P lies to the right of v_i. - if (Below(v->p, vertices[v->previous].p)) { - if (edgeTreeIterators[v->previous] == edgeTree.end()) { - error = true; - break; - } - // If helper(e_i - 1) is a merge vertex. - if (vertextypes[helpers[v->previous]] == TPPL_VERTEXTYPE_MERGE) { - // Insert the diagonal connecting v_i to helper(e_i - 1) in D. - AddDiagonal(vertices, &newnumvertices, vindex, helpers[v->previous], - vertextypes, edgeTreeIterators, &edgeTree, helpers); - vindex2 = newnumvertices - 2; - v2 = &(vertices[vindex2]); - } - // Delete e_i - 1 from T. - edgeTree.erase(edgeTreeIterators[v->previous]); - // Insert e_i in T and set helper(e_i) to v_i. - newedge.p1 = v2->p; - newedge.p2 = vertices[v2->next].p; - newedge.index = vindex2; - edgeTreeRet = edgeTree.insert(newedge); - edgeTreeIterators[vindex2] = edgeTreeRet.first; - helpers[vindex2] = vindex; - } else { - // Search in T to find the edge e_j directly left of v_i. - newedge.p1 = v->p; - newedge.p2 = v->p; - edgeIter = edgeTree.lower_bound(newedge); - if (edgeIter == edgeTree.begin()) { - error = true; - break; - } - edgeIter--; - // If helper(e_j) is a merge vertex. - if (vertextypes[helpers[edgeIter->index]] == TPPL_VERTEXTYPE_MERGE) { - // Insert the diagonal connecting v_i to helper(e_j) in D. - AddDiagonal(vertices, &newnumvertices, vindex, helpers[edgeIter->index], - vertextypes, edgeTreeIterators, &edgeTree, helpers); - } - // helper(e_j) <- v_i. - helpers[edgeIter->index] = vindex; - } - break; - } - - if (error) - break; - } - - char *used = new char[newnumvertices]; - memset(used, 0, newnumvertices * sizeof(char)); - - if (!error) { - // Return result. - long size; - TPPLPoly mpoly; - for (i = 0; i < newnumvertices; i++) { - if (used[i]) { - continue; - } - v = &(vertices[i]); - vnext = &(vertices[v->next]); - size = 1; - while (vnext != v) { - vnext = &(vertices[vnext->next]); - size++; - } - mpoly.Init(size); - v = &(vertices[i]); - mpoly[0] = v->p; - vnext = &(vertices[v->next]); - size = 1; - used[i] = 1; - used[v->next] = 1; - while (vnext != v) { - mpoly[size] = vnext->p; - used[vnext->next] = 1; - vnext = &(vertices[vnext->next]); - size++; - } - monotonePolys->push_back(mpoly); - } - } - - // Cleanup. - delete[] vertices; - delete[] priority; - delete[] vertextypes; - delete[] edgeTreeIterators; - delete[] helpers; - delete[] used; - - if (error) { - return 0; - } else { - return 1; - } -} - -// Adds a diagonal to the doubly-connected list of vertices. -void TPPLPartition::AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2, - TPPLVertexType *vertextypes, std::set::iterator *edgeTreeIterators, - std::set *edgeTree, long *helpers) { - long newindex1, newindex2; - - newindex1 = *numvertices; - (*numvertices)++; - newindex2 = *numvertices; - (*numvertices)++; - - vertices[newindex1].p = vertices[index1].p; - vertices[newindex2].p = vertices[index2].p; - - vertices[newindex2].next = vertices[index2].next; - vertices[newindex1].next = vertices[index1].next; - - vertices[vertices[index2].next].previous = newindex2; - vertices[vertices[index1].next].previous = newindex1; - - vertices[index1].next = newindex2; - vertices[newindex2].previous = index1; - - vertices[index2].next = newindex1; - vertices[newindex1].previous = index2; - - // Update all relevant structures. - vertextypes[newindex1] = vertextypes[index1]; - edgeTreeIterators[newindex1] = edgeTreeIterators[index1]; - helpers[newindex1] = helpers[index1]; - if (edgeTreeIterators[newindex1] != edgeTree->end()) { - edgeTreeIterators[newindex1]->index = newindex1; - } - vertextypes[newindex2] = vertextypes[index2]; - edgeTreeIterators[newindex2] = edgeTreeIterators[index2]; - helpers[newindex2] = helpers[index2]; - if (edgeTreeIterators[newindex2] != edgeTree->end()) { - edgeTreeIterators[newindex2]->index = newindex2; - } -} - -bool TPPLPartition::Below(TPPLPoint &p1, TPPLPoint &p2) { - if (p1.y < p2.y) { - return true; - } else if (p1.y == p2.y) { - if (p1.x < p2.x) { - return true; - } - } - return false; -} - -// Sorts in the falling order of y values, if y is equal, x is used instead. -bool TPPLPartition::VertexSorter::operator()(long index1, long index2) { - if (vertices[index1].p.y > vertices[index2].p.y) { - return true; - } else if (vertices[index1].p.y == vertices[index2].p.y) { - if (vertices[index1].p.x > vertices[index2].p.x) { - return true; - } - } - return false; -} - -bool TPPLPartition::ScanLineEdge::IsConvex(const TPPLPoint &p1, const TPPLPoint &p2, const TPPLPoint &p3) const { - tppl_float tmp; - tmp = (p3.y - p1.y) * (p2.x - p1.x) - (p3.x - p1.x) * (p2.y - p1.y); - if (tmp > 0) { - return 1; - } - - return 0; -} - -bool TPPLPartition::ScanLineEdge::operator<(const ScanLineEdge &other) const { - if (other.p1.y == other.p2.y) { - if (p1.y == p2.y) { - return (p1.y < other.p1.y); - } - return IsConvex(p1, p2, other.p1); - } else if (p1.y == p2.y) { - return !IsConvex(other.p1, other.p2, p1); - } else if (p1.y < other.p1.y) { - return !IsConvex(other.p1, other.p2, p1); - } else { - return IsConvex(p1, p2, other.p1); - } -} - -// Triangulates monotone polygon. -// Time complexity: O(n) -// Space complexity: O(n) -int TPPLPartition::TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles) { - if (!inPoly->Valid()) { - return 0; - } - - long i, i2, j, topindex, bottomindex, leftindex, rightindex, vindex; - TPPLPoint *points = NULL; - long numpoints; - TPPLPoly triangle; - - numpoints = inPoly->GetNumPoints(); - points = inPoly->GetPoints(); - - // Trivial case. - if (numpoints == 3) { - triangles->push_back(*inPoly); - return 1; - } - - topindex = 0; - bottomindex = 0; - for (i = 1; i < numpoints; i++) { - if (Below(points[i], points[bottomindex])) { - bottomindex = i; - } - if (Below(points[topindex], points[i])) { - topindex = i; - } - } - - // Check if the poly is really monotone. - i = topindex; - while (i != bottomindex) { - i2 = i + 1; - if (i2 >= numpoints) { - i2 = 0; - } - if (!Below(points[i2], points[i])) { - return 0; - } - i = i2; - } - i = bottomindex; - while (i != topindex) { - i2 = i + 1; - if (i2 >= numpoints) { - i2 = 0; - } - if (!Below(points[i], points[i2])) { - return 0; - } - i = i2; - } - - char *vertextypes = new char[numpoints]; - long *priority = new long[numpoints]; - - // Merge left and right vertex chains. - priority[0] = topindex; - vertextypes[topindex] = 0; - leftindex = topindex + 1; - if (leftindex >= numpoints) { - leftindex = 0; - } - rightindex = topindex - 1; - if (rightindex < 0) { - rightindex = numpoints - 1; - } - for (i = 1; i < (numpoints - 1); i++) { - if (leftindex == bottomindex) { - priority[i] = rightindex; - rightindex--; - if (rightindex < 0) { - rightindex = numpoints - 1; - } - vertextypes[priority[i]] = -1; - } else if (rightindex == bottomindex) { - priority[i] = leftindex; - leftindex++; - if (leftindex >= numpoints) { - leftindex = 0; - } - vertextypes[priority[i]] = 1; - } else { - if (Below(points[leftindex], points[rightindex])) { - priority[i] = rightindex; - rightindex--; - if (rightindex < 0) { - rightindex = numpoints - 1; - } - vertextypes[priority[i]] = -1; - } else { - priority[i] = leftindex; - leftindex++; - if (leftindex >= numpoints) { - leftindex = 0; - } - vertextypes[priority[i]] = 1; - } - } - } - priority[i] = bottomindex; - vertextypes[bottomindex] = 0; - - long *stack = new long[numpoints]; - long stackptr = 0; - - stack[0] = priority[0]; - stack[1] = priority[1]; - stackptr = 2; - - // For each vertex from top to bottom trim as many triangles as possible. - for (i = 2; i < (numpoints - 1); i++) { - vindex = priority[i]; - if (vertextypes[vindex] != vertextypes[stack[stackptr - 1]]) { - for (j = 0; j < (stackptr - 1); j++) { - if (vertextypes[vindex] == 1) { - triangle.Triangle(points[stack[j + 1]], points[stack[j]], points[vindex]); - } else { - triangle.Triangle(points[stack[j]], points[stack[j + 1]], points[vindex]); - } - triangles->push_back(triangle); - } - stack[0] = priority[i - 1]; - stack[1] = priority[i]; - stackptr = 2; - } else { - stackptr--; - while (stackptr > 0) { - if (vertextypes[vindex] == 1) { - if (IsConvex(points[vindex], points[stack[stackptr - 1]], points[stack[stackptr]])) { - triangle.Triangle(points[vindex], points[stack[stackptr - 1]], points[stack[stackptr]]); - triangles->push_back(triangle); - stackptr--; - } else { - break; - } - } else { - if (IsConvex(points[vindex], points[stack[stackptr]], points[stack[stackptr - 1]])) { - triangle.Triangle(points[vindex], points[stack[stackptr]], points[stack[stackptr - 1]]); - triangles->push_back(triangle); - stackptr--; - } else { - break; - } - } - } - stackptr++; - stack[stackptr] = vindex; - stackptr++; - } - } - vindex = priority[i]; - for (j = 0; j < (stackptr - 1); j++) { - if (vertextypes[stack[j + 1]] == 1) { - triangle.Triangle(points[stack[j]], points[stack[j + 1]], points[vindex]); - } else { - triangle.Triangle(points[stack[j + 1]], points[stack[j]], points[vindex]); - } - triangles->push_back(triangle); - } - - delete[] priority; - delete[] vertextypes; - delete[] stack; - - return 1; -} - -int TPPLPartition::Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles) { - TPPLPolyList monotone; - TPPLPolyList::iterator iter; - - if (!MonotonePartition(inpolys, &monotone)) { - return 0; - } - for (iter = monotone.begin(); iter != monotone.end(); iter++) { - if (!TriangulateMonotone(&(*iter), triangles)) { - return 0; - } - } - return 1; -} - -int TPPLPartition::Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles) { - TPPLPolyList polys; - polys.push_back(*poly); - - return Triangulate_MONO(&polys, triangles); -} \ No newline at end of file diff --git a/src/mapping/map_publishers/lib/polypartition.h b/src/mapping/map_publishers/lib/polypartition.h deleted file mode 100755 index 0da828d59..000000000 --- a/src/mapping/map_publishers/lib/polypartition.h +++ /dev/null @@ -1,419 +0,0 @@ -/*************************************************************************/ -/* Copyright (c) 2011-2021 Ivan Fratric and contributors. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef POLYPARTITION_H -#define POLYPARTITION_H - -#include -#include - -typedef double tppl_float; - -enum TPPLOrientation { - TPPL_ORIENTATION_CW = -1, - TPPL_ORIENTATION_NONE = 0, - TPPL_ORIENTATION_CCW = 1, -}; - -enum TPPLVertexType { - TPPL_VERTEXTYPE_REGULAR = 0, - TPPL_VERTEXTYPE_START = 1, - TPPL_VERTEXTYPE_END = 2, - TPPL_VERTEXTYPE_SPLIT = 3, - TPPL_VERTEXTYPE_MERGE = 4, -}; - -// 2D point structure. -struct TPPLPoint { - tppl_float x; - tppl_float y; - // User-specified vertex identifier. Note that this isn't used internally - // by the library, but will be faithfully copied around. - int id; - - TPPLPoint operator+(const TPPLPoint &p) const { - TPPLPoint r; - r.x = x + p.x; - r.y = y + p.y; - return r; - } - - TPPLPoint operator-(const TPPLPoint &p) const { - TPPLPoint r; - r.x = x - p.x; - r.y = y - p.y; - return r; - } - - TPPLPoint operator*(const tppl_float f) const { - TPPLPoint r; - r.x = x * f; - r.y = y * f; - return r; - } - - TPPLPoint operator/(const tppl_float f) const { - TPPLPoint r; - r.x = x / f; - r.y = y / f; - return r; - } - - bool operator==(const TPPLPoint &p) const { - return ((x == p.x) && (y == p.y)); - } - - bool operator!=(const TPPLPoint &p) const { - return !((x == p.x) && (y == p.y)); - } -}; - -// Polygon implemented as an array of points with a "hole" flag. -class TPPLPoly { - protected: - TPPLPoint *points; - long numpoints; - bool hole; - - public: - // Constructors and destructors. - TPPLPoly(); - ~TPPLPoly(); - - TPPLPoly(const TPPLPoly &src); - TPPLPoly &operator=(const TPPLPoly &src); - - // Getters and setters. - long GetNumPoints() const { - return numpoints; - } - - bool IsHole() const { - return hole; - } - - void SetHole(bool hole) { - this->hole = hole; - } - - TPPLPoint &GetPoint(long i) { - return points[i]; - } - - const TPPLPoint &GetPoint(long i) const { - return points[i]; - } - - TPPLPoint *GetPoints() { - return points; - } - - TPPLPoint &operator[](int i) { - return points[i]; - } - - const TPPLPoint &operator[](int i) const { - return points[i]; - } - - // Clears the polygon points. - void Clear(); - - // Inits the polygon with numpoints vertices. - void Init(long numpoints); - - // Creates a triangle with points p1, p2, and p3. - void Triangle(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3); - - // Inverts the orfer of vertices. - void Invert(); - - // Returns the orientation of the polygon. - // Possible values: - // TPPL_ORIENTATION_CCW: Polygon vertices are in counter-clockwise order. - // TPPL_ORIENTATION_CW: Polygon vertices are in clockwise order. - // TPPL_ORIENTATION_NONE: The polygon has no (measurable) area. - TPPLOrientation GetOrientation() const; - - // Sets the polygon orientation. - // Possible values: - // TPPL_ORIENTATION_CCW: Sets vertices in counter-clockwise order. - // TPPL_ORIENTATION_CW: Sets vertices in clockwise order. - // TPPL_ORIENTATION_NONE: Reverses the orientation of the vertices if there - // is one, otherwise does nothing (if orientation is already NONE). - void SetOrientation(TPPLOrientation orientation); - - // Checks whether a polygon is valid or not. - inline bool Valid() const { return this->numpoints >= 3; } -}; - -#ifdef TPPL_ALLOCATOR -typedef std::list TPPLPolyList; -#else -typedef std::list TPPLPolyList; -#endif - -class TPPLPartition { - protected: - struct PartitionVertex { - bool isActive; - bool isConvex; - bool isEar; - - TPPLPoint p; - tppl_float angle; - PartitionVertex *previous; - PartitionVertex *next; - - PartitionVertex(); - }; - - struct MonotoneVertex { - TPPLPoint p; - long previous; - long next; - }; - - class VertexSorter { - MonotoneVertex *vertices; - -public: - VertexSorter(MonotoneVertex *v) : - vertices(v) {} - bool operator()(long index1, long index2); - }; - - struct Diagonal { - long index1; - long index2; - }; - -#ifdef TPPL_ALLOCATOR - typedef std::list DiagonalList; -#else - typedef std::list DiagonalList; -#endif - - // Dynamic programming state for minimum-weight triangulation. - struct DPState { - bool visible; - tppl_float weight; - long bestvertex; - }; - - // Dynamic programming state for convex partitioning. - struct DPState2 { - bool visible; - long weight; - DiagonalList pairs; - }; - - // Edge that intersects the scanline. - struct ScanLineEdge { - mutable long index; - TPPLPoint p1; - TPPLPoint p2; - - // Determines if the edge is to the left of another edge. - bool operator<(const ScanLineEdge &other) const; - - bool IsConvex(const TPPLPoint &p1, const TPPLPoint &p2, const TPPLPoint &p3) const; - }; - - // Standard helper functions. - bool IsConvex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3); - bool IsReflex(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3); - bool IsInside(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p); - - bool InCone(TPPLPoint &p1, TPPLPoint &p2, TPPLPoint &p3, TPPLPoint &p); - bool InCone(PartitionVertex *v, TPPLPoint &p); - - int Intersects(TPPLPoint &p11, TPPLPoint &p12, TPPLPoint &p21, TPPLPoint &p22); - - TPPLPoint Normalize(const TPPLPoint &p); - tppl_float Distance(const TPPLPoint &p1, const TPPLPoint &p2); - - // Helper functions for Triangulate_EC. - void UpdateVertexReflexity(PartitionVertex *v); - void UpdateVertex(PartitionVertex *v, PartitionVertex *vertices, long numvertices); - - // Helper functions for ConvexPartition_OPT. - void UpdateState(long a, long b, long w, long i, long j, DPState2 **dpstates); - void TypeA(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); - void TypeB(long i, long j, long k, PartitionVertex *vertices, DPState2 **dpstates); - - // Helper functions for MonotonePartition. - bool Below(TPPLPoint &p1, TPPLPoint &p2); - void AddDiagonal(MonotoneVertex *vertices, long *numvertices, long index1, long index2, - TPPLVertexType *vertextypes, std::set::iterator *edgeTreeIterators, - std::set *edgeTree, long *helpers); - - // Triangulates a monotone polygon, used in Triangulate_MONO. - int TriangulateMonotone(TPPLPoly *inPoly, TPPLPolyList *triangles); - - public: - // Simple heuristic procedure for removing holes from a list of polygons. - // It works by creating a diagonal from the right-most hole vertex - // to some other visible vertex. - // Time complexity: O(h*(n^2)), h is the # of holes, n is the # of vertices. - // Space complexity: O(n) - // params: - // inpolys: - // A list of polygons that can contain holes. - // Vertices of all non-hole polys have to be in counter-clockwise order. - // Vertices of all hole polys have to be in clockwise order. - // outpolys: - // A list of polygons without holes. - // Returns 1 on success, 0 on failure. - int RemoveHoles(TPPLPolyList *inpolys, TPPLPolyList *outpolys); - - // Triangulates a polygon by ear clipping. - // Time complexity: O(n^2), n is the number of vertices. - // Space complexity: O(n) - // params: - // poly: - // An input polygon to be triangulated. - // Vertices have to be in counter-clockwise order. - // triangles: - // A list of triangles (result). - // Returns 1 on success, 0 on failure. - int Triangulate_EC(TPPLPoly *poly, TPPLPolyList *triangles); - - // Triangulates a list of polygons that may contain holes by ear clipping - // algorithm. It first calls RemoveHoles to get rid of the holes, and then - // calls Triangulate_EC for each resulting polygon. - // Time complexity: O(h*(n^2)), h is the # of holes, n is the # of vertices. - // Space complexity: O(n) - // params: - // inpolys: - // A list of polygons to be triangulated (can contain holes). - // Vertices of all non-hole polys have to be in counter-clockwise order. - // Vertices of all hole polys have to be in clockwise order. - // triangles: - // A list of triangles (result). - // Returns 1 on success, 0 on failure. - int Triangulate_EC(TPPLPolyList *inpolys, TPPLPolyList *triangles); - - // Creates an optimal polygon triangulation in terms of minimal edge length. - // Time complexity: O(n^3), n is the number of vertices - // Space complexity: O(n^2) - // params: - // poly: - // An input polygon to be triangulated. - // Vertices have to be in counter-clockwise order. - // triangles: - // A list of triangles (result). - // Returns 1 on success, 0 on failure. - int Triangulate_OPT(TPPLPoly *poly, TPPLPolyList *triangles); - - // Triangulates a polygon by first partitioning it into monotone polygons. - // Time complexity: O(n*log(n)), n is the number of vertices. - // Space complexity: O(n) - // params: - // poly: - // An input polygon to be triangulated. - // Vertices have to be in counter-clockwise order. - // triangles: - // A list of triangles (result). - // Returns 1 on success, 0 on failure. - int Triangulate_MONO(TPPLPoly *poly, TPPLPolyList *triangles); - - // Triangulates a list of polygons by first - // partitioning them into monotone polygons. - // Time complexity: O(n*log(n)), n is the number of vertices. - // Space complexity: O(n) - // params: - // inpolys: - // A list of polygons to be triangulated (can contain holes). - // Vertices of all non-hole polys have to be in counter-clockwise order. - // Vertices of all hole polys have to be in clockwise order. - // triangles: - // A list of triangles (result). - // Returns 1 on success, 0 on failure. - int Triangulate_MONO(TPPLPolyList *inpolys, TPPLPolyList *triangles); - - // Creates a monotone partition of a list of polygons that - // can contain holes. Triangulates a set of polygons by - // first partitioning them into monotone polygons. - // Time complexity: O(n*log(n)), n is the number of vertices. - // Space complexity: O(n) - // params: - // inpolys: - // A list of polygons to be triangulated (can contain holes). - // Vertices of all non-hole polys have to be in counter-clockwise order. - // Vertices of all hole polys have to be in clockwise order. - // monotonePolys: - // A list of monotone polygons (result). - // Returns 1 on success, 0 on failure. - int MonotonePartition(TPPLPolyList *inpolys, TPPLPolyList *monotonePolys); - - // Partitions a polygon into convex polygons by using the - // Hertel-Mehlhorn algorithm. The algorithm gives at most four times - // the number of parts as the optimal algorithm, however, in practice - // it works much better than that and often gives optimal partition. - // It uses triangulation obtained by ear clipping as intermediate result. - // Time complexity O(n^2), n is the number of vertices. - // Space complexity: O(n) - // params: - // poly: - // An input polygon to be partitioned. - // Vertices have to be in counter-clockwise order. - // parts: - // Resulting list of convex polygons. - // Returns 1 on success, 0 on failure. - int ConvexPartition_HM(TPPLPoly *poly, TPPLPolyList *parts); - - // Partitions a list of polygons into convex parts by using the - // Hertel-Mehlhorn algorithm. The algorithm gives at most four times - // the number of parts as the optimal algorithm, however, in practice - // it works much better than that and often gives optimal partition. - // It uses triangulation obtained by ear clipping as intermediate result. - // Time complexity O(n^2), n is the number of vertices. - // Space complexity: O(n) - // params: - // inpolys: - // An input list of polygons to be partitioned. Vertices of - // all non-hole polys have to be in counter-clockwise order. - // Vertices of all hole polys have to be in clockwise order. - // parts: - // Resulting list of convex polygons. - // Returns 1 on success, 0 on failure. - int ConvexPartition_HM(TPPLPolyList *inpolys, TPPLPolyList *parts); - - // Optimal convex partitioning (in terms of number of resulting - // convex polygons) using the Keil-Snoeyink algorithm. - // For reference, see M. Keil, J. Snoeyink, "On the time bound for - // convex decomposition of simple polygons", 1998. - // Time complexity O(n^3), n is the number of vertices. - // Space complexity: O(n^3) - // params: - // poly: - // An input polygon to be partitioned. - // Vertices have to be in counter-clockwise order. - // parts: - // Resulting list of convex polygons. - // Returns 1 on success, 0 on failure. - int ConvexPartition_OPT(TPPLPoly *poly, TPPLPolyList *parts); -}; - -#endif \ No newline at end of file diff --git a/src/mapping/map_publishers/package.xml b/src/mapping/map_publishers/package.xml deleted file mode 100755 index f5fccfa8e..000000000 --- a/src/mapping/map_publishers/package.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - map_publishers - 1.0.0 - Nodes for loading and publishing offline maps - Will Heitman - MIT - - ament_cmake - - rclcpp - lanelet2_core - lanelet2_io - lanelet2_projection - lanelet2 - PCL - pcl_conversions - - ament_lint_auto - - - ament_cmake - - diff --git a/src/mapping/map_publishers/src/LaneletLoader.cpp b/src/mapping/map_publishers/src/LaneletLoader.cpp deleted file mode 100755 index c12d36093..000000000 --- a/src/mapping/map_publishers/src/LaneletLoader.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Package: map_publishers - * Filename: GPSInterfaceNode.cpp - * Author: Will Heitman - * Email: Will.Heitman@utdallas.edu - * Copyright: 2021, Nova UTD - * License: MIT License - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "boost/polygon/voronoi.hpp" -#include "boost/polygon/point_data.hpp" -#include "boost/polygon/segment_data.hpp" -#include "polypartition.h" -#include -#include -#include -#include -#include - -#include "rclcpp/rclcpp.hpp" -#include "std_msgs/msg/string.hpp" - -using namespace std::chrono_literals; -/** - * @brief Loads a lanelet .osm file and publishes a visualization - */ -class LaneletLoader : public rclcpp::Node -{ - public: - LaneletLoader() - : Node("lanelet_loader") - { - this->declare_parameter("osm_path", "/home/main/voltron/assets/grand_loop.osm"); - _map = load_from_osm(); - _lanelet_viz_publisher = this->create_publisher("/viz/lanelets", 10); - RCLCPP_INFO_STREAM(this->get_logger(), "Map has "<<_map->laneletLayer.size()<<" lanelets"); - visualizeLanelets(_map); - } - - private: - /** - * @brief Reads osm from path specified in osm_path param - * @return Pointer to loaded lanelet map - */ - lanelet::LaneletMapPtr load_from_osm() { - using namespace lanelet; - this->get_parameter("osm_path", osm_path_); - RCLCPP_INFO_STREAM(this->get_logger(), "Reading map from "<laneletLayer) { - CompoundPolygon2d lanelet_poly = lanelet.polygon2d(); - - auto basic_poly = lanelet_poly.basicPolygon(); - Marker triangleList; - - /** - * We rely on a small lib called "polypartition" to convert - * our lanelet polygon into triangles. Rviz only accepts - * triangles, not more complex polygons. - * See: https://en.wikipedia.org/wiki/Tessellation_(computer_graphics) - */ - TPPLPoly *inpoly = new TPPLPoly(); - TPPLPolyList *triangulationResults = new TPPLPolyList(); - inpoly->Init(basic_poly.size()); - for(uint i=0; iGetPoint(i).x = basic_poly[i][0]; - inpoly->GetPoint(i).y = basic_poly[i][1]; - } - // Orientation of vertices must be set for algorithm to work. - inpoly->SetOrientation(TPPLOrientation::TPPL_ORIENTATION_CCW); - TPPLPartition partitioner; - - // Triangulate using ear clipping - partitioner.Triangulate_EC(inpoly, triangulationResults); - - // Construct an array of Point messages - std::vector triangle_points; - for(TPPLPoly triangle : *triangulationResults) { - Point a; - a.x = triangle[0].x; - a.y = triangle[0].y; - triangle_points.push_back(a); - a.x = triangle[1].x; - a.y = triangle[1].y; - triangle_points.push_back(a); - a.x = triangle[2].x; - a.y = triangle[2].y; - triangle_points.push_back(a); - } - - // Set message header - triangleList.header.stamp = now(); - triangleList.header.frame_id = "map"; - triangleList.ns = "lanelets"; // Set namespace of viz message - triangleList.id = lanelet.id(); // Set unique ID of viz msg - - // Marker type - triangleList.type = triangleList.TRIANGLE_LIST; - triangleList.action = triangleList.MODIFY; - triangleList.points = triangle_points; - - // Create vector for message scale - Vector3 scale_vector; - scale_vector.x = 1; - scale_vector.y = 1; - scale_vector.z = 1; - triangleList.scale = scale_vector; - - // Set color (blue-gray) - ColorRGBA color; - color.r = .588; - color.g = .675; - color.b = .718; - color.a = .8; - triangleList.color = color; - - // Ask Rviz to move our marker with the camera - triangleList.frame_locked = true; - - _lanelet_viz_publisher->publish(triangleList); - } - } - - std::string osm_path_; - lanelet::LaneletMapPtr _map; - rclcpp::Publisher::SharedPtr _lanelet_viz_publisher; -}; - -int main(int argc, char * argv[]) -{ - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} \ No newline at end of file diff --git a/src/mapping/map_publishers/src/PCDLoader.cpp b/src/mapping/map_publishers/src/PCDLoader.cpp deleted file mode 100755 index a384b4b2c..000000000 --- a/src/mapping/map_publishers/src/PCDLoader.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rclcpp/rclcpp.hpp" - -using std::placeholders::_1; -using namespace std::chrono_literals; -using namespace sensor_msgs::msg; -using namespace nav_msgs::msg; - -class PcdLoader : public rclcpp::Node -{ - public: - PcdLoader() - : Node("pcd_loader") - { - this->declare_parameter("pcd_path", "/home/main/voltron/assets/maps/gomentum"); - this->declare_parameter("min_x", -233.0); - this->declare_parameter("min_y", -747.0); - this->declare_parameter("cell_size", 25.0); // Side length of map cell, meters - m_update_interval = this->declare_parameter("update_interval", 3.0); // In seconds - m_pcd_viz_publisher = this->create_publisher("/map/pcd", 10); - - // Lambda function for sub cb-- fancy! - m_gps_odom_sub = this->create_subscription("/gps/odom", 10, - [this](Odometry::SharedPtr msg) { gps_cb(msg); } - ); - } - - private: - /** - * @brief Find map cell that robot is in, then publish appropriate maps - * - * @param msg The odometry message from GPS, used for location - */ - // TODO: Use base_link tf, not GPS. - void gps_cb(Odometry::SharedPtr msg) { - /* - PSEUDOCODE - We want to publish five cells in a plus shape: The cell that the car is in and the 4 adjacent ones. - Get the current base_link location using a tf lookup. - Convert this location to a cell row and column: - - row = y/cell_size (integer division rounds down, which is what we want) - - column = x/cell_size - Load center PCD: {row}_{column}.pcd - Convert to PointCloud2 and publish - */ - double min_x, min_y; - this->get_parameter("cell_size", m_cell_size); - this->get_parameter("min_x", min_x); - this->get_parameter("min_y", min_y); - double current_x = msg->pose.pose.position.x; - double current_y = msg->pose.pose.position.y; - int current_cell_x = (current_x-min_x)/m_cell_size; - int current_cell_y = (current_y-min_y)/m_cell_size; - RCLCPP_DEBUG_STREAM(this->get_logger(), "Current cell: "< crossCloud = getCell(current_cell_x, current_cell_y) - + getCell(current_cell_x+1, current_cell_y) // Publish eastern neighbor - + getCell(current_cell_x-1, current_cell_y) // Western - + getCell(current_cell_x, current_cell_y+1) // Northern - + getCell(current_cell_x, current_cell_y-1) // Southern - + getCell(current_cell_x-1, current_cell_y+1) // NW - + getCell(current_cell_x+1, current_cell_y+1) // NE - + getCell(current_cell_x+1, current_cell_y-1) // SE - + getCell(current_cell_x-1, current_cell_y-1); // SW - - PointCloud2 output_cloud; - pcl::toROSMsg(crossCloud, output_cloud); - - // Set header - output_cloud.header.frame_id = "map"; - output_cloud.header.stamp = this->now(); - - m_pcd_viz_publisher->publish(output_cloud); - } - - /** - * @brief Given map cell, load, convert, and publish PCD. - * - * @param cellx Cell column - * @param celly Cell row - */ - pcl::PointCloud getCell(int cellx, int celly) { - pcl::PointCloud cloud; - this->get_parameter("pcd_path", m_pcd_path); - - // Append map file ("x_y.pcd") to pcd_path param - std::string map_file_path = m_pcd_path+std::to_string(cellx)+"_"+std::to_string(celly)+".pcd"; - - // Try to load file, skipping on failure - if (pcl::io::loadPCDFile (map_file_path, cloud) == -1) { - RCLCPP_WARN_STREAM(this->get_logger(), "Couldn't read map "<::SharedPtr m_gps_odom_sub; - rclcpp::TimerBase::SharedPtr m_pub_timer; - rclcpp::Publisher::SharedPtr m_pcd_viz_publisher; -}; - -int main(int argc, char * argv[]) -{ - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} \ No newline at end of file diff --git a/src/msg/lgsvl_msgs/CHANGELOG.rst b/src/msg/lgsvl_msgs/CHANGELOG.rst deleted file mode 100755 index cbde41807..000000000 --- a/src/msg/lgsvl_msgs/CHANGELOG.rst +++ /dev/null @@ -1,39 +0,0 @@ -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Changelog for package lgsvl_msgs -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -0.0.4 (2020-10-21) ------------------- -* Add VehicleOdometry.msg to README -* Adding VehicleOdometry. -* Update README and LICENSE -* Update package description and maintainers -* Add ultrasonic message. -* Contributors: Guodong Rong, Hadi Tabatabaee, Piotr Jaroszek - -0.0.3 (2020-05-29) ------------------- -* Update readme and license -* Changing some Vector3's to Points where they make more sense. -* Renaming CanBus to CanBusData. -* Adding VehicleStateData. -* Adding VehicleControlData. -* Adding CanBus and DetectedRadarObject/Array. -* Making package hybrid ROS1/ROS2 package. -* Contributors: Hadi Tabatabaee, Joshua Whitley - -0.0.2 (2020-03-04) ------------------- -* Include signal messages in README -* add messages for ground truth signals -* updated license -* Contributors: David Uhm - -0.0.1 (2018-12-18) ------------------- -* add changelog -* update initial version number -* add license -* add Ros package for ground truth messages -* initial commit -* Contributors: David Uhm diff --git a/src/msg/lgsvl_msgs/CMakeLists.txt b/src/msg/lgsvl_msgs/CMakeLists.txt deleted file mode 100755 index e707d9c87..000000000 --- a/src/msg/lgsvl_msgs/CMakeLists.txt +++ /dev/null @@ -1,104 +0,0 @@ -project(lgsvl_msgs) - -find_package(ros_environment REQUIRED) - -set(ROS_VERSION $ENV{ROS_VERSION}) - -set(MSG_FILES - "BoundingBox2D.msg" - "BoundingBox3D.msg" - "CanBusData.msg" - "DetectedRadarObjectArray.msg" - "DetectedRadarObject.msg" - "Detection2D.msg" - "Detection2DArray.msg" - "Detection3D.msg" - "Detection3DArray.msg" - "Signal.msg" - "SignalArray.msg" - "Ultrasonic.msg" - "VehicleControlData.msg" - "VehicleStateData.msg" - "VehicleOdometry.msg" -) - -if(${ROS_VERSION} EQUAL 1) - cmake_minimum_required(VERSION 2.8.3) - - find_package(catkin REQUIRED COMPONENTS - geometry_msgs - message_generation - sensor_msgs - std_msgs - ) - - # Default to C++11 - if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 11) - endif() - - add_message_files( - DIRECTORY msg - FILES ${MSG_FILES} - ) - - generate_messages( - DEPENDENCIES - geometry_msgs - sensor_msgs - std_msgs - ) - - catkin_package( - CATKIN_DEPENDS - message_runtime - geometry_msgs - sensor_msgs - std_msgs - ) -elseif(${ROS_VERSION} EQUAL 2) - cmake_minimum_required(VERSION 3.5) - - find_package(ament_cmake REQUIRED) - find_package(builtin_interfaces REQUIRED) - find_package(geometry_msgs REQUIRED) - find_package(sensor_msgs REQUIRED) - find_package(std_msgs REQUIRED) - find_package(rosidl_default_generators REQUIRED) - - # Default to C++14 - if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_CXX_STANDARD 14) - endif() - - if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") - add_compile_options(-Wall -Wextra -Wpedantic) - endif() - - # Apend "msg/" to each file name - set(TEMP_LIST "") - foreach(MSG_FILE ${MSG_FILES}) - list(APPEND TEMP_LIST "msg/${MSG_FILE}") - endforeach() - set(MSG_FILES ${TEMP_LIST}) - - rosidl_generate_interfaces(${PROJECT_NAME} - ${MSG_FILES} - DEPENDENCIES - builtin_interfaces - geometry_msgs - sensor_msgs - std_msgs - ADD_LINTER_TESTS - ) - - ament_export_dependencies(rosidl_default_runtime) - - if(BUILD_TESTING) - find_package(ament_lint_auto REQUIRED) - ament_lint_auto_find_test_dependencies() - endif() - - ament_package() -endif() diff --git a/src/msg/lgsvl_msgs/README.md b/src/msg/lgsvl_msgs/README.md deleted file mode 100755 index 1e6f6e174..000000000 --- a/src/msg/lgsvl_msgs/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# ROS Package lgsvl_msgs for LG SVL Automotive Simulator - -This repository contains ROS message definitions for lgsvl_msgs to subscribe ROS messages being published by LG SVL Automotive Simulator via rosbridge. - -```text - - Detection3DArray.msg # A list of 3D detections - - Detection3D.msg # 3D detection including id, label, score, and 3D bounding box - - BoundingBox3D.msg # A 3D bounding box definition - - Detection2DArray.msg # A list of 2D detections - - Detection2D.msg # 2D detection including id, label, score, and 2D bounding box - - BoundingBox2D.msg # A 2D bounding box definition - - SignalArray.msg # A list of traffic light detections - - Signal.msg # 3D detection of a traffic light including id, label, score, and 3D bounding box - - CanBusData.msg # Can bus data for an ego vehicle published by the simulator - - VehicleControlData.msg # Vehicle control commands that the simulator subscribes to - - VehicleStateData.msg # Description of the full state of an ego vehicle - - Ultrasonic.msg # Minimum detected distance by an ultrasonic sensor - - VehicleOdometry.msg # Odometry for an ego vehicle -``` - -## Copyright and License - -Copyright (c) 2018-2020 LG Electronics, Inc. - -This software contains code licensed as described in LICENSE. diff --git a/src/msg/lgsvl_msgs/msg/BoundingBox2D.msg b/src/msg/lgsvl_msgs/msg/BoundingBox2D.msg deleted file mode 100755 index c54839f79..000000000 --- a/src/msg/lgsvl_msgs/msg/BoundingBox2D.msg +++ /dev/null @@ -1,4 +0,0 @@ -float32 x # x position of the bounding box center in camera image space, in pixels -float32 y # y position of the bounding box center in camera image space, in pixels -float32 width # width of the bounding box, in pixels -float32 height # height of the bounding box, in pixels diff --git a/src/msg/lgsvl_msgs/msg/BoundingBox3D.msg b/src/msg/lgsvl_msgs/msg/BoundingBox3D.msg deleted file mode 100755 index 830a4c49e..000000000 --- a/src/msg/lgsvl_msgs/msg/BoundingBox3D.msg +++ /dev/null @@ -1,2 +0,0 @@ -geometry_msgs/Pose position # 3D position and orientation of the bounding box center in Lidar space, in meters -geometry_msgs/Vector3 size # Size of the bounding box, in meters diff --git a/src/msg/lgsvl_msgs/msg/CanBusData.msg b/src/msg/lgsvl_msgs/msg/CanBusData.msg deleted file mode 100755 index 4c60883f2..000000000 --- a/src/msg/lgsvl_msgs/msg/CanBusData.msg +++ /dev/null @@ -1,29 +0,0 @@ -std_msgs/Header header - -float32 speed_mps -float32 throttle_pct # 0 to 1 -float32 brake_pct # 0 to 1 -float32 steer_pct # -1 to 1 -bool parking_brake_active -bool high_beams_active -bool low_beams_active -bool hazard_lights_active -bool fog_lights_active -bool left_turn_signal_active -bool right_turn_signal_active -bool wipers_active -bool reverse_gear_active -int8 selected_gear -bool engine_active -float32 engine_rpm -float64 gps_latitude -float64 gps_longitude -float64 gps_altitude -geometry_msgs/Quaternion orientation -geometry_msgs/Vector3 linear_velocities - -int8 GEAR_NEUTRAL = 0 -int8 GEAR_DRIVE = 1 -int8 GEAR_REVERSE = 2 -int8 GEAR_PARKING = 3 -int8 GEAR_LOW = 4 diff --git a/src/msg/lgsvl_msgs/msg/DetectedRadarObject.msg b/src/msg/lgsvl_msgs/msg/DetectedRadarObject.msg deleted file mode 100755 index 69870678e..000000000 --- a/src/msg/lgsvl_msgs/msg/DetectedRadarObject.msg +++ /dev/null @@ -1,18 +0,0 @@ -int32 id - -geometry_msgs/Vector3 sensor_aim -geometry_msgs/Vector3 sensor_right -geometry_msgs/Point sensor_position -geometry_msgs/Vector3 sensor_velocity -float64 sensor_angle - -geometry_msgs/Point object_position -geometry_msgs/Vector3 object_velocity -geometry_msgs/Point object_relative_position -geometry_msgs/Vector3 object_relative_velocity -geometry_msgs/Vector3 object_collider_size -uint8 object_state -bool new_detection - -uint8 STATE_MOVING = 0 -uint8 STATE_STATIONARY = 1 diff --git a/src/msg/lgsvl_msgs/msg/DetectedRadarObjectArray.msg b/src/msg/lgsvl_msgs/msg/DetectedRadarObjectArray.msg deleted file mode 100755 index d20f8ca25..000000000 --- a/src/msg/lgsvl_msgs/msg/DetectedRadarObjectArray.msg +++ /dev/null @@ -1,3 +0,0 @@ -std_msgs/Header header - -lgsvl_msgs/DetectedRadarObject[] objects diff --git a/src/msg/lgsvl_msgs/msg/Detection2D.msg b/src/msg/lgsvl_msgs/msg/Detection2D.msg deleted file mode 100755 index 0802869b7..000000000 --- a/src/msg/lgsvl_msgs/msg/Detection2D.msg +++ /dev/null @@ -1,6 +0,0 @@ -std_msgs/Header header -uint32 id # The numeric ID of the detected object -string label # car, pedestrian -float32 score # The confidence score of the detected object in the range [0-1] -BoundingBox2D bbox # A 2D bounding box -geometry_msgs/Twist velocity # Linear and angular velocity diff --git a/src/msg/lgsvl_msgs/msg/Detection2DArray.msg b/src/msg/lgsvl_msgs/msg/Detection2DArray.msg deleted file mode 100755 index 250d3e683..000000000 --- a/src/msg/lgsvl_msgs/msg/Detection2DArray.msg +++ /dev/null @@ -1,2 +0,0 @@ -std_msgs/Header header -Detection2D[] detections # A list of 2D detections diff --git a/src/msg/lgsvl_msgs/msg/Detection3D.msg b/src/msg/lgsvl_msgs/msg/Detection3D.msg deleted file mode 100755 index 552fb80a9..000000000 --- a/src/msg/lgsvl_msgs/msg/Detection3D.msg +++ /dev/null @@ -1,6 +0,0 @@ -std_msgs/Header header -uint32 id # The numeric ID of the detected object -string label # car, pedestrian -float32 score # The confidence score of the detected object in the range [0-1] -BoundingBox3D bbox # A 3D bounding box -geometry_msgs/Twist velocity # Linear and angular velocity diff --git a/src/msg/lgsvl_msgs/msg/Detection3DArray.msg b/src/msg/lgsvl_msgs/msg/Detection3DArray.msg deleted file mode 100755 index 348a10d0f..000000000 --- a/src/msg/lgsvl_msgs/msg/Detection3DArray.msg +++ /dev/null @@ -1,2 +0,0 @@ -std_msgs/Header header -Detection3D[] detections # A list of 3D detections diff --git a/src/msg/lgsvl_msgs/msg/Signal.msg b/src/msg/lgsvl_msgs/msg/Signal.msg deleted file mode 100755 index 5ac2b9393..000000000 --- a/src/msg/lgsvl_msgs/msg/Signal.msg +++ /dev/null @@ -1,5 +0,0 @@ -std_msgs/Header header -uint32 id # The numeric ID of the detected signal -string label # green, yellow, red -float32 score # The confidence score of the detected signal in the range [0-1] -BoundingBox3D bbox # A 3D bounding box diff --git a/src/msg/lgsvl_msgs/msg/SignalArray.msg b/src/msg/lgsvl_msgs/msg/SignalArray.msg deleted file mode 100755 index 5de7c787a..000000000 --- a/src/msg/lgsvl_msgs/msg/SignalArray.msg +++ /dev/null @@ -1,2 +0,0 @@ -std_msgs/Header header -Signal[] signals # A list of traffic signals diff --git a/src/msg/lgsvl_msgs/msg/Ultrasonic.msg b/src/msg/lgsvl_msgs/msg/Ultrasonic.msg deleted file mode 100755 index 1719e21fd..000000000 --- a/src/msg/lgsvl_msgs/msg/Ultrasonic.msg +++ /dev/null @@ -1,2 +0,0 @@ -std_msgs/Header header -float32 minimum_distance diff --git a/src/msg/lgsvl_msgs/msg/VehicleControlData.msg b/src/msg/lgsvl_msgs/msg/VehicleControlData.msg deleted file mode 100755 index 7e8d5cfe2..000000000 --- a/src/msg/lgsvl_msgs/msg/VehicleControlData.msg +++ /dev/null @@ -1,13 +0,0 @@ -std_msgs/Header header - -float32 acceleration_pct # 0 to 1 -float32 braking_pct # 0 to 1 -float32 target_wheel_angle # radians -float32 target_wheel_angular_rate # radians / second -uint8 target_gear - -uint8 GEAR_NEUTRAL = 0 -uint8 GEAR_DRIVE = 1 -uint8 GEAR_REVERSE = 2 -uint8 GEAR_PARKING = 3 -uint8 GEAR_LOW = 4 diff --git a/src/msg/lgsvl_msgs/msg/VehicleOdometry.msg b/src/msg/lgsvl_msgs/msg/VehicleOdometry.msg deleted file mode 100755 index 74290735e..000000000 --- a/src/msg/lgsvl_msgs/msg/VehicleOdometry.msg +++ /dev/null @@ -1,5 +0,0 @@ -std_msgs/Header header - -float32 velocity # meters / second -float32 front_wheel_angle # radians -float32 rear_wheel_angle # radians diff --git a/src/msg/lgsvl_msgs/msg/VehicleStateData.msg b/src/msg/lgsvl_msgs/msg/VehicleStateData.msg deleted file mode 100755 index 6ad08a41f..000000000 --- a/src/msg/lgsvl_msgs/msg/VehicleStateData.msg +++ /dev/null @@ -1,36 +0,0 @@ -std_msgs/Header header - -uint8 blinker_state -uint8 headlight_state -uint8 wiper_state -uint8 current_gear -uint8 vehicle_mode -bool hand_brake_active -bool horn_active -bool autonomous_mode_active - -uint8 BLINKERS_OFF = 0 -uint8 BLINKERS_LEFT = 1 -uint8 BLINKERS_RIGHT = 2 -uint8 BLINKERS_HAZARD = 3 - -uint8 HEADLIGHTS_OFF = 0 -uint8 HEADLIGHTS_LOW = 1 -uint8 HEADLIGHTS_HIGH = 2 - -uint8 WIPERS_OFF = 0 -uint8 WIPERS_LOW = 1 -uint8 WIPERS_MED = 2 -uint8 WIPERS_HIGH = 3 - -uint8 GEAR_NEUTRAL = 0 -uint8 GEAR_DRIVE = 1 -uint8 GEAR_REVERSE = 2 -uint8 GEAR_PARKING = 3 -uint8 GEAR_LOW = 4 - -uint8 VEHICLE_MODE_COMPLETE_MANUAL = 0 -uint8 VEHICLE_MODE_COMPLETE_AUTO_DRIVE = 1 -uint8 VEHICLE_MODE_AUTO_STEER_ONLY = 2 -uint8 VEHICLE_MODE_AUTO_SPEED_ONLY = 3 -uint8 VEHICLE_MODE_EMERGENCY_MODE = 4 diff --git a/src/msg/lgsvl_msgs/package.xml b/src/msg/lgsvl_msgs/package.xml deleted file mode 100755 index df7650f5c..000000000 --- a/src/msg/lgsvl_msgs/package.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - lgsvl_msgs - 0.0.4 - Message definitions for interfacing with the LGSVL Simulator for ROS and ROS 2. - Hadi Tabatabaee - David Uhm - BSD - David Uhm - - catkin - ament_cmake - - message_generation - rosidl_default_generators - ros_environment - - builtin_interfaces - geometry_msgs - sensor_msgs - std_msgs - - message_runtime - rosidl_default_runtime - - ament_lint_auto - ament_lint_common - - rosidl_interface_packages - - - catkin - ament_cmake - - diff --git a/src/msg/nova_msgs/msg/Masses.msg b/src/msg/nova_msgs/msg/Masses.msg index e63dd2d25..1c9b02a7c 100644 --- a/src/msg/nova_msgs/msg/Masses.msg +++ b/src/msg/nova_msgs/msg/Masses.msg @@ -9,4 +9,4 @@ std_msgs/Header header float32[] occ float32[] free int32 width -int32 height +int32 height \ No newline at end of file diff --git a/src/msg/nova_msgs/msg/Mode.msg b/src/msg/nova_msgs/msg/Mode.msg new file mode 100644 index 000000000..407e3951c --- /dev/null +++ b/src/msg/nova_msgs/msg/Mode.msg @@ -0,0 +1,5 @@ +uint8 DISABLED=0 +uint8 MANUAL=1 +uint8 AUTO=2 + +uint8 mode \ No newline at end of file diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/prediction.msg b/src/msg/nova_msgs/msg/Prediction.msg similarity index 100% rename from src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/prediction.msg rename to src/msg/nova_msgs/msg/Prediction.msg diff --git a/src/msg/nova_msgs/package.xml b/src/msg/nova_msgs/package.xml index 70506f501..bb18e7f76 100755 --- a/src/msg/nova_msgs/package.xml +++ b/src/msg/nova_msgs/package.xml @@ -13,10 +13,11 @@ action_msgs builtin_interfaces geometry_msgs + nav_msgs sensor_msgs shape_msgs std_msgs - + rosidl_default_runtime rosidl_interface_packages diff --git a/src/msg/nova_msgs/srv/GetLandmarks.srv b/src/msg/nova_msgs/srv/GetLandmarks.srv new file mode 100644 index 000000000..0487e2f9b --- /dev/null +++ b/src/msg/nova_msgs/srv/GetLandmarks.srv @@ -0,0 +1,4 @@ +--- +geometry_msgs/Point[] speed_limit_signs +geometry_msgs/Point[] stop_signs +geometry_msgs/Point[] traffic_lights diff --git a/src/msg/nova_msgs/srv/SafetyCommand.srv b/src/msg/nova_msgs/srv/SafetyCommand.srv deleted file mode 100755 index 29d850884..000000000 --- a/src/msg/nova_msgs/srv/SafetyCommand.srv +++ /dev/null @@ -1,24 +0,0 @@ -# Package: nova_msgs -# Filename: SafetyCommand.srv -# Author: Joshua Williams -# Email: joshmackwilliams@protonmail.com -# Copyright: 2021, Nova UTD -# License: MIT License - -# The service the safety manager uses to assign recovery strategies to nodes -# See https://github.com/Nova-UTD/navigator/wiki/Safety-Manager-Design - -# Which of the node's strategies to use -# 0 is reserved for normal operation -# 255 is reserved for termination -uint8 strategy - -# Sequence number, to ensure messages can't be processed out of order -uint32 sequence_number - -# JSON-formatted command-specific data -string additional_data - ---- - -# We send nothing back, but this is used as an acknowledgement \ No newline at end of file diff --git a/src/msg/nova_msgs/srv/SafetyEvent.srv b/src/msg/nova_msgs/srv/SafetyEvent.srv deleted file mode 100755 index 2262bba11..000000000 --- a/src/msg/nova_msgs/srv/SafetyEvent.srv +++ /dev/null @@ -1,34 +0,0 @@ -# Package: nova_msgs -# Filename: SafetyEvent.srv -# Author: Joshua Williams -# Email: joshmackwilliams@protonmail.com -# Copyright: 2021, Nova UTD -# License: MIT License - -# The service nodes use to notify the safety manager of an issue -# See https://github.com/Nova-UTD/navigator/wiki/Safety-Manager-Design - -# A unique identifier for the type of this event -uint64 event_uid - -# Sequence number, to ensure messages can't be processed out of order -uint32 sequence_number - -# The current status - see below for values -uint8 status -# The node is working on assessing or resolving the event locally -uint8 STATUS_WORKING = 0 -# The node cannot resolve the event locally -uint8 STATUS_UNRESOLVED = 1 -# The event is resolved -uint8 STATUS_RESOLVED = 2 - -# A human-readable description, for debugging and visualization purposes only -string description - -# JSON-formatted event-specific data -string additional_data - ---- - -# We send nothing back, but this is used as an acknowledgement \ No newline at end of file diff --git a/src/perception/ROSOccupancyGridPrediction/LICENSE b/src/perception/ROSOccupancyGridPrediction/LICENSE deleted file mode 100644 index 3c44c2a4d..000000000 --- a/src/perception/ROSOccupancyGridPrediction/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Stanford Intelligent Systems Laboratory - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/perception/ROSOccupancyGridPrediction/NOTES.md b/src/perception/ROSOccupancyGridPrediction/NOTES.md deleted file mode 100644 index 3f235ff68..000000000 --- a/src/perception/ROSOccupancyGridPrediction/NOTES.md +++ /dev/null @@ -1,67 +0,0 @@ -# General -Supports both TensorFlow and PyTorch. Since we already have PyTorch installed, let's use that. - -The prediction result is a 20 x 2 x 128 x 128 array: -- from t = [0,19] -- Both occupied and unoccupied? -- 128 x 128 cells (0.33m resolution, ~43 meters) - -# Messages -## DDLPointType -Typedef to `lidar_msgs::PointXYZIDBS`, where each point has xyz, intensity, device ID, beam ID, and score (?). - -## Masses -Appears to be a custom Occupancy Grid message, with separate arrays for occupied and free probabilities. "It contains masses for DST [Dempster-Shafer -Theory] occupancy grid calculation and prediction." - -## Prediction -Array of `nav_msgs/OccupancyGrid` - -# Components -## AggregatePoints -The Ford AV dataset includes four LiDAR sensors named Red, Yellow, Green, and Blue. This node simply adds them into a single point cloud and publishes it to `/agg_points` - -## FrameBroadcaster -Appears to send a transform from `body -> global_pcl_frame` that rotates 90 degrees about the z axis. - -## InferenceTorch -### `onInit()` -Publishes to both `/prediction` (single OccupancyGrid) and `/prediction_all` (Prediction msg, just an array of OccupancyGrids). - -Subscribes to `/masses`, which is a DST-formatted occupancy grid. - -1. Loads model from `models/` -2. Initializes subs, pubs, and timer - -### `timerCallback` -Every 1 ms (at best): -1. `createTensorFromFrames` ("Processing masses") -2. `Infer` ("Making predictions") -3. `Publish` ("Publishing the prediction") - -### `masses_callback` -Collects `masses` data (DT-style occupancy grids) into a vector of length 5. - -## MrfGroundSeg -Markov Random Field ground segmentation. Subscribes to `/agg_points` and publishes the filtered cloud to `/mrf_filtered_points` - -Published result preserves all "raw" fields for each point, including device ID, beam ID, and score. - -## OccupancyGridGeneration -Publishes a standard OccupancyGrid message with 128x128 cells. Resolution is ~0.33 meters, so grid is ~42x42 meters, centered on the car. - -Used to rely on upstream vehicle localization to determine the car's change in position at each update. *Now assumes that the change is zero-- e.g. that the car is stationary.* - -Call stack: -1. `cloud_cb` (on each message received from ground seg) - 1. `create_DST_grid` - 1. `add_points_to_the_DST` - 2. `add_free_spaces_to_the_DST` - 3. `add_ego_vehicle_to_the_DST` - -Functions operate on global variables, so they don't take arguments. - -## Visualize -Subscribes to `/prediction_all` (array of OccupancyGrids). - -Loops through each prediction layer from t = [4, 20), publishes it to `/visualization`, and moves to the next layer after 0.1 seconds. \ No newline at end of file diff --git a/src/perception/ROSOccupancyGridPrediction/README.md b/src/perception/ROSOccupancyGridPrediction/README.md deleted file mode 100644 index e4a3c5b1f..000000000 --- a/src/perception/ROSOccupancyGridPrediction/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# ROS Occupancy Grid Prediction - -This package contains ROS C++ Occupancy Grid Prediction framework which includes point cloud preprocessing, ground segementation, occupancy grid generation, and occupancy grid prediction. The pipeline follows the approach defined by Itkina et al. [1]. The package is compatible with models trained in Tensorflow and PyTorch provided as protocol buffers (.pb) and torch script (.pt), respectively. It contains PredNet [1], PredNet with TAAConvLSTM, and PredNet with SAAConvLSTM [2] models trained on the KITTI dataset [3]. Pointcloud can be provided in the form of a rosbag or directly from the robot Lidar sensors. This package does not contain the Tensorflow C++ API and LibTorch API (PyTorch C++), and the rosbags. The package is fully compatible with [Ford AV Dataset](https://avdata.ford.com/) [4]. - -## ROS Lidar pointcloud compatibility - -Frame and topics names are compatible with Ford AV Dataset. To ensure the compatibility with other rosbag, the raw Lidar pointcloud topics needs to be renamed in the aggregate_points.cpp to match the topics and the number of Lidar sensors in the rosbag. The type of message used to represent the Lidar pointcloud and all other messages are defined in lidar_msgs. - -## How to run it? - -1. Install Ford AV dataset ROS package and all dependencies from [Ford AV Dataset](https://avdata.ford.com/) [4] in your catkin_workspace. - -2. Replace the multi_lidar_convert.launch in ford_demo/launch with the file provided in other. - -3. Provide the path to the prediction model in inference_torch.cpp (or inference_tf.cpp). Example models are provided in the lidar_pkg/models. If tensorflow models is used, also define the name of the input and output layer in the following lines. - -4. In the same terminal, launch the node. Pick the right launch file depending if you are doing inference using Tensorflow or LibTorch. - - ```bash - roslaunch lidar_pkg launch_all.launch - ``` -5. In a different terminal, start a rosbag from AV Dataset. Ensure that the naming convention of the topics is correct. - - ```bash - rosbag play --clock path/to/the/rosbag - ``` -6. In the terminal with rosbag play command, press SPACE to stop/resume the rosbag. To see the predictions, press SPACE (pause). Predictions will appear to the right of the occupancy grid. - -## Example of the rviz visualization - -![](images/ROS_demo.gif) - -## Experiments - -Tested on: -- Ubuntu 18.04 -- ROS Melodic -- Tensorflow r2.3 for CUDA 11.0 (compiled from source and linked accordingly in the CMake files, follow [official Tensorflow instructions](https://www.tensorflow.org/install/source)) -- LibTorch 1.8.0 for CUDA 11.0 (binary downloaded from [PyTorch website](https://pytorch.org/cppdocs/installing.html)) -- CUDA 11.0 -- Nvidia RTX 2080Ti -- Intel i9-9900KF - -Performance: - -| Models | Publish rate using Tensorflow (Hz) | Publish rate using LibTorch (Hz) | -| ------------- |:-------------:| -----:| -| PredNet | 9.7 ± 0.52 | 13.5 ± 0.34 | -| PredNet with TAAConvLSTM | - | 6.5 ± 0.49 | -| PredNet with SAAConvLSTM | - | 5.1 ± 0.45 | - -## Acknowledgements -The authors would like to acknowledge this project being made possible by the funding from the Ford-Stanford Alliance. The authors thank Stanford Dynamic Design Lab for providing Lidar processing stack. - -Maintained by [Bernard Lange](https://web.stanford.edu/~blange/) - -## References - -[1] Itkina, M., Driggs-Campbell, K. and Kochenderfer, M.J., 2019, Dynamic Environment Prediction in Urban Scenes using Recurrent Representation Learning. In IEEE Intelligent Transportation Systems Conference (ITSC), pp. 2052-2059. - -[2] Lange, B., Itkina, M. and Kochenderfer, M.J., 2020. Attention Augmented ConvLSTM for Environment Prediction. arXiv preprint arXiv:2010.09662. - -[3] Geiger, A., Lenz, P., Stiller, C. and Urtasun, R., 2013. Vision meets robotics: The kitti dataset. The International Journal of Robotics Research, 32(11), pp. 1231-1237. - -[4] Agarwal, S., Vora, A., Pandey, G., Williams, W., Kourous, H. and McBride, J., 2020. Ford Multi-AV Seasonal Dataset. arXiv preprint arXiv:2003.07969. - - - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/CMakeLists.txt b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/CMakeLists.txt deleted file mode 100644 index df01c287a..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/CMakeLists.txt +++ /dev/null @@ -1,228 +0,0 @@ -cmake_minimum_required(VERSION 2.8.3) -project(lidar_msgs) - -## Compile as C++11, supported in ROS Kinetic and newer -# add_compile_options(-std=c++11) - -## Find catkin macros and libraries -## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) -## is used, also find other catkin packages -find_package(catkin REQUIRED COMPONENTS - pcl_ros - std_msgs - geometry_msgs - sensor_msgs - nav_msgs - roscpp - rospy - message_generation - roslib - pcl_conversions -) - -## System dependencies are found with CMake's conventions -# find_package(Boost REQUIRED COMPONENTS system) -#find_package(PkgConfig) -find_package(PCL REQUIRED) - - -## Uncomment this if the package has a setup.py. This macro ensures -## modules and global scripts declared therein get installed -## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html -# catkin_python_setup() - -################################################ -## Declare ROS messages, services and actions ## -################################################ - -## To declare and build messages, services or actions from within this -## package, follow these steps: -## * Let MSG_DEP_SET be the set of packages whose message types you use in -## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). -## * In the file package.xml: -## * add a build_depend tag for "message_generation" -## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET -## * If MSG_DEP_SET isn't empty the following dependency has been pulled in -## but can be declared for certainty nonetheless: -## * add a run_depend tag for "message_runtime" -## * In this file (CMakeLists.txt): -## * add "message_generation" and every package in MSG_DEP_SET to -## find_package(catkin REQUIRED COMPONENTS ...) -## * add "message_runtime" and every package in MSG_DEP_SET to -## catkin_package(CATKIN_DEPENDS ...) -## * uncomment the add_*_files sections below as needed -## and list every .msg/.srv/.action file to be processed -## * uncomment the generate_messages entry below -## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) - -## Generate messages in the 'msg' folder -add_message_files( - FILES - pointCloud.msg - point.msg - masses.msg - prediction.msg - future_masses.msg - vehicle_state.msg -) - -add_library(${PROJECT_NAME} - src/vehicle_data.cpp -) - -## Generate services in the 'srv' folder -# add_service_files( -# FILES -# Service1.srv -# Service2.srv -# ) - -## Generate actions in the 'action' folder -# add_action_files( -# FILES -# Action1.action -# Action2.action -# ) - -## Generate added messages and services with any dependencies listed here -generate_messages( - DEPENDENCIES - std_msgs - nav_msgs -) - -################################################ -## Declare ROS dynamic reconfigure parameters ## -################################################ - -## To declare and build dynamic reconfigure parameters within this -## package, follow these steps: -## * In the file package.xml: -## * add a build_depend and a run_depend tag for "dynamic_reconfigure" -## * In this file (CMakeLists.txt): -## * add "dynamic_reconfigure" to -## find_package(catkin REQUIRED COMPONENTS ...) -## * uncomment the "generate_dynamic_reconfigure_options" section below -## and list every .cfg file to be processed - -## Generate dynamic reconfigure parameters in the 'cfg' folder -# generate_dynamic_reconfigure_options( -# cfg/DynReconf1.cfg -# cfg/DynReconf2.cfg -# ) - -################################### -## catkin specific configuration ## -################################### -## The catkin_package macro generates cmake config files for your package -## Declare things to be passed to dependent projects -## INCLUDE_DIRS: uncomment this if your package contains header files -## LIBRARIES: libraries you create in this project that dependent projects also need -## CATKIN_DEPENDS: catkin_packages dependent projects also need -## DEPENDS: system dependencies of this project that dependent projects also need -catkin_package( - INCLUDE_DIRS include - LIBRARIES lidar_msgs - CATKIN_DEPENDS - std_msgs - geometry_msgs - sensor_msgs - roscpp - rospy - message_runtime - #DEPENDS system_lib -) - -########### -## Build ## -########### - -## Specify additional locations of header files -## Your package locations should be listed before other locations -include_directories( - include - ${PCL_INCLUDE_DIRS} - ${catkin_INCLUDE_DIRS} -) -link_directories(${PCL_LIBRARY_DIRS}) -add_definitions(${PCL_DEFINITIONS}) - -## Declare a C++ library -# add_library(${PROJECT_NAME} -# src/${PROJECT_NAME}/lidar_msgs.cpp -# ) - -## Add cmake target dependencies of the library -## as an example, code may need to be generated before libraries -## either from message generation or dynamic reconfigure -add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) - -## Declare a C++ executable -## With catkin_make all packages are built within a single CMake context -## The recommended prefix ensures that target names across packages don't collide -# add_executable(${PROJECT_NAME}_node src/lidar_msgs_node.cpp) -#add_executable(aggregate_points src/aggregate_points.cpp) - -## Rename C++ executable without prefix -## The above recommended prefix causes long target names, the following renames the -## target back to the shorter version for ease of user use -## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node" -# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") - -## Add cmake target dependencies of the executable -## same as for the library above -# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) - -## Specify libraries to link a library or executable target against -# target_link_libraries(${PROJECT_NAME}_node -# ${catkin_LIBRARIES} -# ) -#target_link_libraries(aggregate_points ${catkin_LIBRARIES} ${PCL_LIBRARIES}) - -############# -## Install ## -############# - -# all install targets should use catkin DESTINATION variables -# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html - -## Mark executable scripts (Python etc.) for installation -## in contrast to setup.py, you can choose the destination -# install(PROGRAMS -# scripts/my_python_script -# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} -# ) - -## Mark executables and/or libraries for installation -# install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_node -# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} -# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} -# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} -# ) - -## Mark cpp header files for installation -# install(DIRECTORY include/${PROJECT_NAME}/ -# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} -# FILES_MATCHING PATTERN "*.h" -# PATTERN ".svn" EXCLUDE -# ) - -## Mark other files for installation (e.g. launch and bag files, etc.) -# install(FILES -# # myfile1 -# # myfile2 -# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} -# ) - -############# -## Testing ## -############# - -## Add gtest based cpp test target and link libraries -# catkin_add_gtest(${PROJECT_NAME}-test test/test_lidar_msgs.cpp) -# if(TARGET ${PROJECT_NAME}-test) -# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) -# endif() - -## Add folders to be run by python nosetests -# catkin_add_nosetests(test) diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/include/lidar_msgs/point_types.h b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/include/lidar_msgs/point_types.h deleted file mode 100644 index d85c909d4..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/include/lidar_msgs/point_types.h +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -namespace lidar_msgs -{ - struct PointXYZIDBS - { - PCL_ADD_POINT4D; - // float intensity; - // uint16_t device_id; - // uint16_t beam_id; - // float score; - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - } EIGEN_ALIGN16; -}; - -POINT_CLOUD_REGISTER_POINT_STRUCT(lidar_msgs::PointXYZIDBS, - (float, x, x) - (float, y, y) - (float, z, z)) - - // (float, intensity, intensity) - // (uint16_t, device_id, device_id) - // (uint16_t, beam_id, beam_id) - // (float, score, score) - -typedef lidar_msgs::PointXYZIDBS DDLPointType; -typedef pcl::PointCloud DDLPointCloud; diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/include/lidar_msgs/vehicle_data.h b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/include/lidar_msgs/vehicle_data.h deleted file mode 100644 index b5d0c627a..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/include/lidar_msgs/vehicle_data.h +++ /dev/null @@ -1,31 +0,0 @@ -// #pragma once - -#include -#include - -namespace lidar_msgs -{ - -class VehicleData{ - - private: - lidar_msgs::vehicle_state ros_vehicleState; - double psi_rad; - double N_m; - double E_m; - public: - - /* Constructors */ - VehicleData(); - VehicleData(const lidar_msgs::vehicle_state& vehicleState); - - /* Setters & Getters */ - void setState(const lidar_msgs::vehicle_state& vehicleState); - - void getPose(double& E_m, double& N_m, double& psi_rad) const; - void getPoseWrtE(double& E_m, double& N_m, double& psi_rad) const; - - /* Miscellaneous */ -}; - -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/future_masses.msg b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/future_masses.msg deleted file mode 100644 index cc0abcce9..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/future_masses.msg +++ /dev/null @@ -1,7 +0,0 @@ -#It contains masses for DST occupancy grid calculation and prediction. -#Occ - occupied masses. -#Free - free masses. -#Stored in a row-major order, starting with (0,0). Values in the range [0,1]. - -masses[] predictions - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/masses.msg b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/masses.msg deleted file mode 100644 index afdc76f0a..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/masses.msg +++ /dev/null @@ -1,11 +0,0 @@ -#It contains masses for DST occupancy grid calculation and prediction. -#Occ - occupied masses. -#Free - free masses. -#Stored in a row-major order, starting with (0,0). Values in the range [0,1]. - -Header header # ROS defined header containing timestamp and sequence id - -float32[] occ -float32[] free -int32 width -int32 height diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/point.msg b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/point.msg deleted file mode 100644 index 8b42b1076..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/point.msg +++ /dev/null @@ -1,9 +0,0 @@ -# -------------- /point.msg ---------------- -# Custom ROS message for points - -Header header # ROS defined header containing timestamp and sequence id - -float64 x -float64 y -float64 z -float64 intensity diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/pointCloud.msg b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/pointCloud.msg deleted file mode 100644 index 0fdec8f72..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/pointCloud.msg +++ /dev/null @@ -1,22 +0,0 @@ -# -------------- /pointCloud.msg ---------------- -# Custom ROS message for point clouds - -Header header # ROS defined header containing timestamp and sequence id - -# information about points - -int64 num_points # Number of points defined in points array -lidar_msgs/point[] points # Array of points - -# information about lasers - -float64[] range_m -float64[] theta -float64[] phi -int64[] firing -int64[] sorted - -# information about lidars - -int64 num_lidars -int64[] lidar_id diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/vehicle_state.msg b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/vehicle_state.msg deleted file mode 100644 index 3ba9509ea..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/msg/vehicle_state.msg +++ /dev/null @@ -1,6 +0,0 @@ -# Custom ROS message for vehicle state information - -Header header # Ros defined header containing timestamp and sequence id -float64 psi_rad # Heading [rad] -float64 N_m # N position [m] -float64 E_m # E position [m] diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/package.xml b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/package.xml deleted file mode 100644 index a8a27b49b..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/package.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - lidar_msgs - 0.0.0 - The lidar_msgs package - - - - - Gene Lewis - - - - - - TODO - - - - - - - - - - - - Gene Lewis - - - - - - - - - - - - - message_generation - std_msgs - geometry_msgs - sensor_msgs - roscpp - rospy - pcl_ros - - - message_generation - std_msgs - geometry_msgs - sensor_msgs - - - - catkin - - - message_runtime - std_msgs - geometry_msgs - sensor_msgs - roscpp - rospy - pcl_ros - - - - - - - - - - - - - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/src/vehicle_data.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_msgs/src/vehicle_data.cpp deleted file mode 100644 index d600ab0e5..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_msgs/src/vehicle_data.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - - -namespace lidar_msgs -{ - - -VehicleData::VehicleData(){} - -VehicleData::VehicleData(const lidar_msgs::vehicle_state& vehicleState){ - setState(vehicleState); -} - -void VehicleData::setState(const lidar_msgs::vehicle_state& vehicleState){ - this->psi_rad = vehicleState.psi_rad; - this->N_m = vehicleState.N_m; - this->E_m = vehicleState.E_m; -} - -void VehicleData::getPose(double& E_m, double& N_m, double& psi_rad) const { - E_m = this->E_m; - N_m = this->N_m; - psi_rad = this->psi_rad; -} - -void VehicleData::getPoseWrtE(double& E_m, double& N_m, double& psi_rad) const { - E_m = this->E_m; - N_m = this->N_m; - psi_rad = this->psi_rad + M_PI_2; -} - -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/CMakeLists.txt b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/CMakeLists.txt deleted file mode 100644 index 1a0772fbb..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/CMakeLists.txt +++ /dev/null @@ -1,92 +0,0 @@ -cmake_minimum_required(VERSION 2.8.3) -set(CMAKE_CXX_STANDARD 14) -project(lidar_pkg) - - -list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules) -list(APPEND CMAKE_PREFIX_PATH "/usr/local/libtorch") - -find_package(catkin REQUIRED COMPONENTS - lidar_msgs - nodelet - roscpp - lidar_msgs - rospy - std_msgs - geometry_msgs - sensor_msgs - nav_msgs - roslib - pcl_conversions - pcl_ros - message_filters - tf2 - tf2_ros - tf -) - -## Setup include directories -include_directories(${catkin_INCLUDE_DIRS}) - - -catkin_package( -# INCLUDE_DIRS include -# LIBRARIES nodelet_plugins -# CATKIN_DEPENDS -# lidar_msgs -# roscpp -# rospy -# std_msgs -# DEPENDS system_lib -) - -## Create the nodelet tutorial library -add_library(nodelet_plugins - src/aggregate_points.cpp - src/aggregate_points.h - src/mrf_ground_seg.cpp - src/occupancy_grid_generation.cpp - src/occupancy_grid_generation.h - src/inference_tf.cpp - src/inference_tf.h - src/inference_torch.cpp - src/inference_torch.h - src/utils.cpp - src/utils.h - src/visualize.cpp - src/visualize.h - ) - -find_package(Torch REQUIRED) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}") -set_property(TARGET nodelet_plugins PROPERTY CXX_STANDARD 14) - -target_link_libraries(nodelet_plugins "${TORCH_LIBRARIES}") -target_link_libraries(nodelet_plugins tensorflow_cc ${catkin_LIBRARIES} ${PROJECT_LIBRARIES} "${TORCH_LIBRARIES}") - - -if(catkin_EXPORTED_LIBRARIES) - add_dependencies(nodelet_plugins ${catkin_EXPORTED_LIBRARIES}) -endif() - -## Mark the nodelet library for installations -install(TARGETS nodelet_plugins - ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} - LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} - RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}) - -install(FILES nodelet_plugins.xml mynodelet.launch - DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}) - -# add modules -list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules") - -# find packages -find_package(TensorFlow REQUIRED) -find_package(Protobuf REQUIRED) - -set(PROJECT_INCLUDE_DIRS ${TensorFlow_INCLUDE_DIRS} ${PROTOBUF_INCLUDE_DIRS}) -set(PROJECT_LIBRARIES ${TensorFlow_LIBRARIES} ${PROTOBUF_LIBRARIES}) - -include_directories(${PROJECT_INCLUDE_DIRS}) -target_link_libraries(nodelet_plugins tensorflow_cc ${PROJECT_LIBRARIES} ${catkin_LIBRARIES}) diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/cmake/Modules/FindTensorFlow.cmake b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/cmake/Modules/FindTensorFlow.cmake deleted file mode 100644 index 5661b3fb5..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/cmake/Modules/FindTensorFlow.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# Locates the tensorFlow library and include directories. - -include(FindPackageHandleStandardArgs) -unset(TENSORFLOW_FOUND) - -find_path(TensorFlow_INCLUDE_DIR - NAMES - tensorflow/core - tensorflow/cc - third_party - HINTS - /usr/local/include/google/tensorflow - /usr/include/google/tensorflow) - - -find_library(TensorFlow_LIBRARY NAMES tensorflow_all - HINTS - /usr/lib - /usr/local/lib) - -find_library(TensorFlow_LIBRARY NAMES tensorflow_cc - HINTS - /usr/lib - /usr/local/lib) - -find_library(TensorFlow_LIBRARY NAMES tensorflow_framework - HINTS - /usr/lib - /usr/local/lib) - -# set TensorFlow_FOUND -find_package_handle_standard_args(TensorFlow DEFAULT_MSG TensorFlow_INCLUDE_DIR TensorFlow_LIBRARY) - -# set external variables for usage in CMakeLists.txt -if(TENSORFLOW_FOUND) - set(TensorFlow_LIBRARIES ${TensorFlow_LIBRARY}) - set(TensorFlow_INCLUDE_DIRS ${TensorFlow_INCLUDE_DIR}) -endif() - -# hide locals from GUI -mark_as_advanced(TensorFlow_INCLUDE_DIR TensorFlow_LIBRARY) - -#set(CXX_FLAGS “-Wall -undefined dynamic_lookup”) -#set(CMAKE_CXX_FLAGS “${CXX_FLAGS}”) diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/Lidar_stack_with_tensorflow.launch b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/Lidar_stack_with_tensorflow.launch deleted file mode 100644 index e275ec49d..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/Lidar_stack_with_tensorflow.launch +++ /dev/null @@ -1,24 +0,0 @@ - - - - - --> - - - - - - - - - - - - - - - - - - - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/Lidar_stack_with_torch.launch b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/Lidar_stack_with_torch.launch deleted file mode 100644 index 64c75bc22..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/Lidar_stack_with_torch.launch +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - --> - - - - - - - - - - - - - - - - - - - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/launch_all.launch b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/launch_all.launch deleted file mode 100644 index 5b8cced91..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/launch/launch_all.launch +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/nodelet_plugins.xml b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/nodelet_plugins.xml deleted file mode 100644 index 4596a1389..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/nodelet_plugins.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - Write things here. - - - - - - Write things here. - - - - - - Write things here. - - - - - - Write things here. - - - - - - Write things here. - - - - - - Write things here. - - - - - - Write things here. - - - - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/package.xml b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/package.xml deleted file mode 100644 index 3cb73ba08..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/package.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - lidar_pkg - 0.0.0 - The lidar_pkg package - - - - - ford - - - - - - TODO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - catkin - lidar_filter_points - lidar_msgs - nodelet - roscpp - lidar_filter_points - lidar_msgs - nodelet - roscpp - lidar_filter_points - lidar_msgs - nodelet - roscpp - - - - - - - - - - - diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/rviz/tensorflow_viz.rviz b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/rviz/tensorflow_viz.rviz deleted file mode 100644 index eeab785cf..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/rviz/tensorflow_viz.rviz +++ /dev/null @@ -1,184 +0,0 @@ -Panels: - - Class: rviz/Displays - Help Height: 78 - Name: Displays - Property Tree Widget: - Expanded: - - /Global Options1 - - /Status1 - - /PointCloud21 - - /Map1 - - /Map1/Status1 - - /Map1/Position1 - - /Map1/Orientation1 - - /Axes1 - - /Map2 - Splitter Ratio: 0.5 - Tree Height: 721 - - Class: rviz/Selection - Name: Selection - - Class: rviz/Tool Properties - Expanded: - - /2D Pose Estimate1 - - /2D Nav Goal1 - - /Publish Point1 - Name: Tool Properties - Splitter Ratio: 0.5886790156364441 - - Class: rviz/Views - Expanded: - - /Current View1 - Name: Views - Splitter Ratio: 0.5 - - Class: rviz/Time - Experimental: false - Name: Time - SyncMode: 0 - SyncSource: PointCloud2 -Preferences: - PromptSaveOnExit: true -Toolbars: - toolButtonStyle: 2 -Visualization Manager: - Class: "" - Displays: - - Alpha: 0.5 - Cell Size: 1 - Class: rviz/Grid - Color: 160; 160; 164 - Enabled: true - Line Style: - Line Width: 0.029999999329447746 - Value: Lines - Name: Grid - Normal Cell Count: 0 - Offset: - X: 0 - Y: 0 - Z: 0 - Plane: XY - Plane Cell Count: 10 - Reference Frame: - Value: true - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz/PointCloud2 - Color: 255; 255; 255 - Color Transformer: Intensity - Decay Time: 0 - Enabled: true - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 251 - Min Color: 0; 0; 0 - Min Intensity: 11 - Name: PointCloud2 - Position Transformer: XYZ - Queue Size: 10 - Selectable: true - Size (Pixels): 3 - Size (m): 0.05999999865889549 - Style: Flat Squares - Topic: /OccupancyGridGeneration/mrf_filtered_points - Unreliable: false - Use Fixed Frame: true - Use rainbow: true - Value: true - - Alpha: 0.699999988079071 - Class: rviz/Map - Color Scheme: map - Draw Behind: false - Enabled: true - Name: Map - Topic: /InferenceTF/occupancy - Unreliable: false - Use Timestamp: false - Value: true - - Class: rviz/Axes - Enabled: true - Length: 1.5 - Name: Axes - Radius: 0.5 - Reference Frame: vehicle_cg_cartesian - Value: true - - Alpha: 0.699999988079071 - Class: rviz/Map - Color Scheme: map - Draw Behind: false - Enabled: true - Name: Map - Topic: /Visualize/visualization - Unreliable: false - Use Timestamp: false - Value: true - Enabled: true - Global Options: - Background Color: 48; 48; 48 - Default Light: true - Fixed Frame: vehicle_cg_cartesian - Frame Rate: 30 - Name: root - Tools: - - Class: rviz/Interact - Hide Inactive Objects: true - - Class: rviz/MoveCamera - - Class: rviz/Select - - Class: rviz/FocusCamera - - Class: rviz/Measure - - Class: rviz/SetInitialPose - Theta std deviation: 0.2617993950843811 - Topic: /initialpose - X std deviation: 0.5 - Y std deviation: 0.5 - - Class: rviz/SetGoal - Topic: /move_base_simple/goal - - Class: rviz/PublishPoint - Single click: true - Topic: /clicked_point - Value: true - Views: - Current: - Class: rviz/Orbit - Distance: 175.34107971191406 - Enable Stereo Rendering: - Stereo Eye Separation: 0.05999999865889549 - Stereo Focal Distance: 1 - Swap Stereo Eyes: false - Value: false - Focal Point: - X: 15.894294738769531 - Y: -8.109152793884277 - Z: 11.52355670928955 - Focal Shape Fixed Size: true - Focal Shape Size: 0.05000000074505806 - Invert Z Axis: false - Name: Current View - Near Clip Distance: 0.009999999776482582 - Pitch: 0.7497983574867249 - Target Frame: - Value: Orbit (rviz) - Yaw: 4.698549270629883 - Saved: ~ -Window Geometry: - Displays: - collapsed: false - Height: 1018 - Hide Left Dock: false - Hide Right Dock: true - QMainWindow State: 000000ff00000000fd0000000400000000000001560000035cfc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d0000035c000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000259fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d00000259000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000003dc0000003efc0100000002fb0000000800540069006d00650100000000000003dc000002eb00fffffffb0000000800540069006d00650100000000000004500000000000000000000002800000035c00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 - Selection: - collapsed: false - Time: - collapsed: false - Tool Properties: - collapsed: false - Views: - collapsed: true - Width: 988 - X: 932 - Y: 27 diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/rviz/torch_viz.rviz b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/rviz/torch_viz.rviz deleted file mode 100644 index 7d7fa7337..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/rviz/torch_viz.rviz +++ /dev/null @@ -1,183 +0,0 @@ -Panels: - - Class: rviz/Displays - Help Height: 78 - Name: Displays - Property Tree Widget: - Expanded: - - /Global Options1 - - /Status1 - - /PointCloud21 - - /Map1 - - /Map1/Position1 - - /Map1/Orientation1 - - /Axes1 - - /Map2 - Splitter Ratio: 0.5 - Tree Height: 721 - - Class: rviz/Selection - Name: Selection - - Class: rviz/Tool Properties - Expanded: - - /2D Pose Estimate1 - - /2D Nav Goal1 - - /Publish Point1 - Name: Tool Properties - Splitter Ratio: 0.5886790156364441 - - Class: rviz/Views - Expanded: - - /Current View1 - Name: Views - Splitter Ratio: 0.5 - - Class: rviz/Time - Experimental: false - Name: Time - SyncMode: 0 - SyncSource: "" -Preferences: - PromptSaveOnExit: true -Toolbars: - toolButtonStyle: 2 -Visualization Manager: - Class: "" - Displays: - - Alpha: 0.5 - Cell Size: 1 - Class: rviz/Grid - Color: 160; 160; 164 - Enabled: true - Line Style: - Line Width: 0.029999999329447746 - Value: Lines - Name: Grid - Normal Cell Count: 0 - Offset: - X: 0 - Y: 0 - Z: 0 - Plane: XY - Plane Cell Count: 10 - Reference Frame: - Value: true - - Alpha: 1 - Autocompute Intensity Bounds: true - Autocompute Value Bounds: - Max Value: 10 - Min Value: -10 - Value: true - Axis: Z - Channel Name: intensity - Class: rviz/PointCloud2 - Color: 255; 255; 255 - Color Transformer: Intensity - Decay Time: 0 - Enabled: false - Invert Rainbow: false - Max Color: 255; 255; 255 - Max Intensity: 220 - Min Color: 0; 0; 0 - Min Intensity: 11 - Name: PointCloud2 - Position Transformer: XYZ - Queue Size: 10 - Selectable: true - Size (Pixels): 3 - Size (m): 0.05999999865889549 - Style: Flat Squares - Topic: /MrfGroundSeg/agg_points - Unreliable: false - Use Fixed Frame: true - Use rainbow: true - Value: false - - Alpha: 0.699999988079071 - Class: rviz/Map - Color Scheme: map - Draw Behind: false - Enabled: true - Name: Map - Topic: /InferenceTorch/occupancy - Unreliable: false - Use Timestamp: false - Value: true - - Class: rviz/Axes - Enabled: true - Length: 1.5 - Name: Axes - Radius: 0.5 - Reference Frame: global_pcl_frame - Value: true - - Alpha: 0.699999988079071 - Class: rviz/Map - Color Scheme: map - Draw Behind: false - Enabled: true - Name: Map - Topic: /Visualize/visualization - Unreliable: false - Use Timestamp: false - Value: true - Enabled: true - Global Options: - Background Color: 48; 48; 48 - Default Light: true - Fixed Frame: global_pcl_frame - Frame Rate: 30 - Name: root - Tools: - - Class: rviz/Interact - Hide Inactive Objects: true - - Class: rviz/MoveCamera - - Class: rviz/Select - - Class: rviz/FocusCamera - - Class: rviz/Measure - - Class: rviz/SetInitialPose - Theta std deviation: 0.2617993950843811 - Topic: /initialpose - X std deviation: 0.5 - Y std deviation: 0.5 - - Class: rviz/SetGoal - Topic: /move_base_simple/goal - - Class: rviz/PublishPoint - Single click: true - Topic: /clicked_point - Value: true - Views: - Current: - Class: rviz/Orbit - Distance: 123.50437927246094 - Enable Stereo Rendering: - Stereo Eye Separation: 0.05999999865889549 - Stereo Focal Distance: 1 - Swap Stereo Eyes: false - Value: false - Focal Point: - X: 22.355911254882812 - Y: -1.618168830871582 - Z: -9.910804748535156 - Focal Shape Fixed Size: true - Focal Shape Size: 0.05000000074505806 - Invert Z Axis: false - Name: Current View - Near Clip Distance: 0.009999999776482582 - Pitch: 1.5697963237762451 - Target Frame: - Value: Orbit (rviz) - Yaw: 3.1517174243927 - Saved: ~ -Window Geometry: - Displays: - collapsed: true - Height: 1018 - Hide Left Dock: true - Hide Right Dock: true - QMainWindow State: 000000ff00000000fd0000000400000000000001560000035cfc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073000000003d0000035c000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000259fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073000000003d00000259000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000002eb0000003efc0100000002fb0000000800540069006d00650100000000000002eb000002eb00fffffffb0000000800540069006d00650100000000000004500000000000000000000002eb0000035c00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 - Selection: - collapsed: false - Time: - collapsed: false - Tool Properties: - collapsed: false - Views: - collapsed: true - Width: 747 - X: 64 - Y: 32 diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/aggregate_points.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/aggregate_points.cpp deleted file mode 100644 index e77d6c7c0..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/aggregate_points.cpp +++ /dev/null @@ -1,153 +0,0 @@ -#include -#include "aggregate_points.h" - -PLUGINLIB_EXPORT_CLASS(lidar_pkg::AggregatePoints, nodelet::Nodelet) - -namespace lidar_pkg -{ - void AggregatePoints::onInit() - { - ROS_INFO("Initialized AggregatePoints Nodelet"); - ros::NodeHandle& private_nh = getPrivateNodeHandle(); - pub = private_nh.advertise>("agg_points",1); //pcl::PointCloud sensor_msgs::PointCloud2 - //filter.setVehicle(vehicle_msg); //??????????????????? - - yellow_sub = private_nh.subscribe("velo_yellow_points", 1, &AggregatePoints::yellow_cb, this); - red_sub = private_nh.subscribe("velo_red_points", 1, &AggregatePoints::red_cb, this); - blue_sub = private_nh.subscribe("velo_blue_points", 1, &AggregatePoints::blue_cb, this); - green_sub = private_nh.subscribe("velo_green_points", 1, &AggregatePoints::green_cb, this); - timer = private_nh.createTimer(ros::Duration(0.1),&AggregatePoints::timerCallback, this); - } - - void AggregatePoints::timerCallback(const ros::TimerEvent&) - { - pub.publish(agg_cloud); - } - - void AggregatePoints::aggregate_cloud() - { - agg_cloud = yellow_cloud; - this->agg_cloud += this->red_cloud; - this->agg_cloud += this->green_cloud; - this->agg_cloud += this->blue_cloud; - } - - void AggregatePoints::yellow_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg) - { - pcl::PCLPointCloud2 pcl_pc2; - pcl_conversions::toPCL(*pcMsg,pcl_pc2); - pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud); - pcl::fromPCLPointCloud2(pcl_pc2,*temp_cloud); - pcl_ros::transformPointCloud("body", ros::Time::now(), *temp_cloud, "map",yellow_cloud,tfListener); - aggregate_cloud(); - } - - void AggregatePoints::red_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg) - { - pcl::PCLPointCloud2 pcl_pc2; - pcl_conversions::toPCL(*pcMsg,pcl_pc2); - pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud); - pcl::fromPCLPointCloud2(pcl_pc2,*temp_cloud); - pcl_ros::transformPointCloud("body", ros::Time::now(), *temp_cloud, "map",red_cloud,tfListener); - aggregate_cloud(); - } - - void AggregatePoints::blue_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg) - { - pcl::PCLPointCloud2 pcl_pc2; - pcl_conversions::toPCL(*pcMsg,pcl_pc2); - pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud); - pcl::fromPCLPointCloud2(pcl_pc2,*temp_cloud); - pcl_ros::transformPointCloud("body", ros::Time::now(), *temp_cloud, "map",blue_cloud,tfListener); - aggregate_cloud(); - } - - void AggregatePoints::green_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg) - { - pcl::PCLPointCloud2 pcl_pc2; - pcl_conversions::toPCL(*pcMsg,pcl_pc2); - pcl::PointCloud::Ptr temp_cloud(new pcl::PointCloud); - pcl::fromPCLPointCloud2(pcl_pc2,*temp_cloud); - pcl_ros::transformPointCloud("body", ros::Time::now(), *temp_cloud, "map",green_cloud,tfListener); - aggregate_cloud(); - } - - // void CloudFilter::filter(sensor_msgs::PointCloud2 &cloud) - // { - // ROS_INFO("Filtering..."); - // this->filt_cloud.header = cloud.header; - // this->filt_cloud.clear(); - // - // bool include; - // for(DDLPointCloud::iterator it = cloud.begin(); it != cloud.end(); it++){ - // bool include = true; - // //if(this->device_id >= 0) include = include && isDeviceAndBeam(*it); - // //if(this->min_intensity > 0) include = include && isAboveIntensity(*it); - // //if(this->max_height > 0) include = include && isBelowHeight(*it); - // // include = include && isAboveHeight(*it); - // // include = include && isLocallyBelowHeight(*it); - // // include = include && isBelowMaxDistance(*it); - // if(include) this->filt_cloud.push_back(*it); - // } - // cloud = this->filt_cloud; - // } - - // bool CloudFilter::isDeviceAndBeam(sensor_msgs::PointCloud2 pt){ - // if(pt.device_id == this->device_id){ - // if(this->beam_id < 0 || pt.beam_id == this->beam_id){ - // return true; - // } - // } - // return false; - // } - - // bool CloudFilter::isAboveIntensity(sensor_msgs::PointCloud2 pt){ - // if(pt.intensity > this->min_intensity){ - // return true; - // } - // return false; - // } - - // bool CloudFilter::isAboveDistance(sensor_msgs::PointCloud2 pt){ - // double x_dist = pt.x - E_m; - // double y_dist = pt.y - N_m; - // if(x_dist*x_dist + y_dist*y_dist > this->min_distance*this->min_distance){ - // return true; - // } - // return false; - // } - // - // bool CloudFilter::isBelowHeight(sensor_msgs::PointCloud2 pt){ - // if(pt.z < this->max_height) return true; - // return false; - // } - // - // bool CloudFilter::isAboveHeight(sensor_msgs::PointCloud2 pt){ - // if(pt.z > this->min_height) return true; - // return false; - // } - // - // bool CloudFilter::isLocallyBelowHeight(sensor_msgs::PointCloud2 pt){ - // if(!isAboveDistance(pt) && pt.z >= this->max_local_height){ - // return false; - // sensor_msgs::PointCloud22 - // return true; - // } - // - // bool CloudFilter::isBelowMaxDistance(sensor_msgs::PointCloud2 pt){ - // double x_dist = pt.x - E_m; - // double y_dist = pt.y - N_m; - // if(x_dist*x_dist + y_dist*y_dist < this->max_distance*this->max_distance){ - // return true; - // } - // return false; - // } - - // void CloudFilter::setVehicle(lidar_msgs::VehicleData vehicle){ - // this->vehicle = vehicle; - // double psi_rad; - // this->vehicle.getPose(this->E_m, this->N_m, psi_rad); - // // ROS_INFO("GETTING POSE in CloudFilter::setVehicle"); - // // std::cout << "E_m and N_m: " << E_m << " " << N_m << std::endl; - // } -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/aggregate_points.h b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/aggregate_points.h deleted file mode 100644 index 60381592a..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/aggregate_points.h +++ /dev/null @@ -1,100 +0,0 @@ -#include "ros/ros.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -namespace lidar_pkg -{ - class CloudFilter - { - public: - CloudFilter(){}; - CloudFilter(int min_intensity, double min_distance, double max_distance, double min_height, double max_height, double max_local_height){ - // this->device_id = device_id; - // this->beam_id = beam_id; - this->min_intensity = min_intensity; - this->min_distance = min_distance; - this->max_distance = max_distance; - this->min_height = min_height; - this->max_height = max_height; - this->max_local_height = max_local_height; - } - - void filter(sensor_msgs::PointCloud2 &cloud); - void setVehicle(lidar_msgs::VehicleData vehicle); - - private: - // int device_id; - // int beam_id; - int min_intensity; - double min_distance; - double max_distance; - double min_height; - double max_height; - double max_local_height; - pcl::PointCloud filt_cloud; - - lidar_msgs::VehicleData vehicle; - double E_m = 0.0; - double N_m = 0.0; - - bool isDeviceAndBeam(pcl::PointCloud pt); - bool isAboveIntensity(pcl::PointCloud pt); - bool isAboveDistance(pcl::PointCloud pt); - bool isBelowHeight(pcl::PointCloud pt); - bool isAboveHeight(pcl::PointCloud pt); - bool isLocallyBelowHeight(pcl::PointCloud pt); - bool isBelowMaxDistance(pcl::PointCloud pt); - }; - - class AggregatePoints : public nodelet::Nodelet - { - public: - AggregatePoints(){} - private: - ros::Publisher pub; - pcl::PointCloud agg_cloud; - pcl::PointCloud yellow_cloud; - pcl::PointCloud red_cloud; - pcl::PointCloud blue_cloud; - pcl::PointCloud green_cloud; - pcl::PointCloud velo_cloud; - lidar_msgs::VehicleData vehicle_msg; - CloudFilter filter; - tf::TransformListener tfListener; - - ros::Subscriber yellow_sub; - ros::Subscriber red_sub; - ros::Subscriber blue_sub; - ros::Subscriber green_sub; - ros::Subscriber velo_sub; - ros::Subscriber veh_sub; - ros::Timer timer; - tf::TransformListener listener; - - virtual void onInit(); - void aggregate_cloud(); - void yellow_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg); - void red_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg); - void blue_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg); - void green_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg); - void velo_cb(const sensor_msgs::PointCloud2::ConstPtr &pcMsg); - void vehicleCallback(const lidar_msgs::vehicle_state& vehicleState); - void timerCallback(const ros::TimerEvent&); - }; -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/frame_broadcaster.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/frame_broadcaster.cpp deleted file mode 100644 index 96ca21df2..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/frame_broadcaster.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -int main(int argc, char** argv){ - ros::init(argc, argv, "my_tf_broadcaster"); - ros::NodeHandle node; - - ros::Rate rate(10.0); - double change = 0; - while (node.ok()){ - tf::TransformBroadcaster br; - tf::Transform transform; - transform.setRotation( tf::Quaternion(0, 0, 0.7071068, 0.7071068) ); - - br.sendTransform(transform, ros::Time::now(), "body", "global_pcl_frame"); - rate.sleep(); - } - return 0; -}; diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_tf.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_tf.cpp deleted file mode 100644 index 57f1466b0..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_tf.cpp +++ /dev/null @@ -1,239 +0,0 @@ -#include -#include -#include -#include "inference_tf.h" -#include "utils.h" - -#include -#include -#include -#include -#include -#include - -#include "tensorflow/core/public/session.h" -#include "tensorflow/cc/ops/const_op.h" -#include "tensorflow/cc/ops/array_ops.h" -#include "tensorflow/cc/ops/standard_ops.h" -#include "tensorflow/core/framework/graph.pb.h" -#include "tensorflow/core/graph/default_device.h" -#include "tensorflow/core/graph/graph_def_builder.h" -#include "tensorflow/core/lib/core/threadpool.h" -#include "tensorflow/core/lib/io/path.h" -#include "tensorflow/core/lib/strings/stringprintf.h" -#include "tensorflow/core/platform/init_main.h" -#include "tensorflow/core/public/session.h" -#include "tensorflow/core/util/command_line_flags.h" -#include "tensorflow/cc/framework/ops.h" -#include -#include -#include - -PLUGINLIB_EXPORT_CLASS(lidar_pkg::InferenceTF, nodelet::Nodelet) - -namespace lidar_pkg -{ - void InferenceTF::onInit() - { - ROS_INFO("Initialized InferenceTF."); - tensorflow::Tensor input(tensorflow::DT_FLOAT, tensorflow::TensorShape({1,20,128,128,2})); - ros::NodeHandle& private_nh = getMTPrivateNodeHandle(); - // Set dirs variables - std::string graphPath = "/home/bernard/catkin_ws/src/ROS_OGP/ROSOccupancyGridPrediction/models/prednet_1.pb"; - std::string GRAPH = "prednet_1.pb"; - - // Set input & output nodes names - inputLayer = "input_1_1:0"; - outputLayer = "pred_net_1_1/transpose_1:0"; - - // Load and initialize the model from .pb file - ROS_INFO("Getting the graph..."); - // std::string graphPath = tensorflow::io::JoinPath(ROOTDIR, GRAPH); - ROS_INFO("Loading the graph..."); - tensorflow::Status loadGraphStatus = loadGraph(graphPath, &session); - if (!loadGraphStatus.ok()) { - ROS_INFO("Not loaded"); - //return 0; - } - else - { - ROS_INFO("Loaded"); - } - - pred_pub = private_nh.advertise("prediction", 1); - pred_all_pub = private_nh.advertise("prediction_all", 1); - occupancy_grid_sub = private_nh.subscribe("occupancy", 1, &InferenceTF::occupancy_grid_callback, this); - masses_sub = private_nh.subscribe("masses", 1, &InferenceTF::masses_callback, this); - timer = private_nh.createTimer(ros::Duration(0.001), &InferenceTF::timerCallback, this); - } - - void InferenceTF::timerCallback(const ros::TimerEvent&) - { - if (data_acquired==true) - { - ROS_INFO("Inside the timer"); - - //DEFINE APPROPRAITE GLOBAL VARIABLES - - tensorflow::Tensor input(tensorflow::DT_FLOAT, tensorflow::TensorShape({1,20,128,128,2})); - std::vector output; - - // Create/Fill in a tensor. - - createTensorFromFrames(input); - std::cout << "BEFORE THE SESSION RUNNING" << std::endl; - output.clear(); - tensorflow::Status runStatus = session->Run({{inputLayer, input}}, {outputLayer}, {}, &output); - std::cout << "AFTER THE SESSION RUNNING" << std::endl; - - if (!runStatus.ok()) { - std::cout << "Running model failed: " << runStatus; - //return 0; - } - else { - ROS_INFO("Prediction made"); - } - createPredictionAndPublish(output); - //saveTensor(output); - } - else { - ROS_INFO("Clock is paused not realy but yeah"); - } - } - - void InferenceTF::createPredictionAndPublish(std::vector& output) - { - ROS_INFO("Publishing"); - int grid_size = 128; - prediction_msg.prediction.clear(); - auto output_values = output[0].tensor(); - int probability; - for (unsigned int t = 0; t < 20; t++){ - occupancy_msg.data.clear(); - occupancy_msg.info.resolution = 1./3.; - occupancy_msg.info.width = grid_size; - occupancy_msg.info.height = grid_size; - for (unsigned int i = 0; i < grid_size; i++){ - for (unsigned int j = 0; j < grid_size; j++){ - probability = (int)(100*(0.5*output_values(0,t,i,j,0)+0.5*(1.0 - output_values(0,t,i,j,1)))); - occupancy_msg.data.push_back(probability); - } - } - prediction_msg.prediction.push_back(occupancy_msg); - } - pred_all_pub.publish(prediction_msg); - pred_pub.publish(occupancy_msg); - } - - void InferenceTF::saveTensor(std::vector& output) - { - auto output_values = output[0].tensor(); - for(unsigned int t=0;t<20;t++){ - std::vector occ; - std::vector free; - - for(unsigned int x=0;x<128;x++){ - for(unsigned int y=0;y<128;y++){ - occ.push_back(output_values(0,t,x,y,0)); - free.push_back(output_values(0,t,x,y,1)); - } - } - std::ofstream outfile_occ("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/prediction_occ"+std::to_string(t)+".txt"); - for (const auto &e : occ) outfile_occ << e << "\n"; - - std::ofstream outfile_free("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/prediction_free"+std::to_string(t)+".txt"); - for (const auto &e : free) outfile_free << e << "\n"; - - } - } - - void InferenceTF::createTensorFromFrames(tensorflow::Tensor& input) - { - using namespace::tensorflow::ops; - tensorflow::Status status; - auto root = tensorflow::Scope::NewRootScope(); - std::unique_ptr session(tensorflow::NewSession({})); - tensorflow::GraphDef graph; - bool past = true; - auto input_map = input.tensor(); - lidar_msgs::masses data; - ROS_INFO("STARTED_SAVING"); - for(unsigned int t = 0; t<20;t++){ - if (t<5){ - data = history_m[t]; - //saveFrame(data,t); - } - else { - past = false; - } - int count = 0; - for(unsigned int x = 0; x<128;x++){ - for(unsigned int y = 0; y<128;y++){ - if(past==true){ - input_map(0,t,x,y,0) = (float)data.occ[count]; //check the ordering + add depth. - input_map(0,t,x,y,1) = (float)data.free[count]; - } - else{ - //input_map(0,t,x,y,0) = 0.0; - //input_map(0,t,x,y,1) = 0.0; - } - count++; - } - } - } - //history_m.clear(); - //history_n.clear(); - } - - void InferenceTF::saveFrame(lidar_msgs::masses& data, int t) - { - std::vector occ; - occ = data.occ; - std::vector free; - free = data.free; - std::ofstream outfile_occ("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/past_occ"+std::to_string(t)+".txt"); - for (const auto &e : occ) outfile_occ << e << "\n"; - - std::ofstream outfile_free("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/past_free"+std::to_string(t)+".txt"); - for (const auto &e : free) outfile_free << e << "\n"; - - } - - void InferenceTF::occupancy_grid_callback(const nav_msgs::OccupancyGrid::ConstPtr& occupancy) - { - ROS_INFO("Data collected"); - time++; - nav_msgs::OccupancyGrid zeross; - //zeross.data = occupancy.data; - if (time <= 5){ - history_n.push_back(*occupancy); - } - else { - data_acquired = true; - for (unsigned int i=0; i<=3; i++){ - history_n[i] = history_n[i+1]; - } - history_n[4]=(*occupancy); - } - ROS_INFO("Done with Data collected"); - } - - void InferenceTF::masses_callback(const lidar_msgs::masses::ConstPtr& masses_data) - { - ROS_INFO("Data collected Masses"); - //time++; - nav_msgs::OccupancyGrid zeross; - //zeross.data = occupancy.data; - if (time <= 5){ - history_m.push_back(*masses_data); - } - else { - data_acquired = true; - for (unsigned int i=0; i<=3; i++){ - history_m[i] = history_m[i+1]; - } - history_m[4] = (*masses_data); - } - ROS_INFO("Done with Data collected"); - } -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_tf.h b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_tf.h deleted file mode 100644 index 6df1ade7a..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_tf.h +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "tensorflow/core/public/session.h" -#include "tensorflow/cc/ops/const_op.h" -#include "tensorflow/cc/ops/array_ops.h" -#include "tensorflow/cc/ops/standard_ops.h" -#include "tensorflow/core/framework/graph.pb.h" -#include "tensorflow/core/graph/default_device.h" -#include "tensorflow/core/graph/graph_def_builder.h" -#include "tensorflow/core/lib/core/threadpool.h" -#include "tensorflow/core/lib/io/path.h" -#include "tensorflow/core/lib/strings/stringprintf.h" -#include "tensorflow/core/platform/init_main.h" -#include "tensorflow/core/public/session.h" -#include "tensorflow/core/util/command_line_flags.h" -#include "tensorflow/cc/framework/ops.h" - -#include -#include -#include - -typedef int DST_mass[128][128][3]; - -namespace lidar_pkg { - class InferenceTF : public nodelet::Nodelet - { - public: - InferenceTF(){}; - private: - ros::Publisher pred_pub; - ros::Publisher pred_all_pub; - ros::Subscriber occupancy_grid_sub; - ros::Subscriber masses_sub; - ros::Timer timer; - std::vector> history; - std::vector history_n; - std::vector history_m; - std::unique_ptr session; - std::string inputLayer; - std::string outputLayer; - nav_msgs::OccupancyGrid occupancy_msg; - lidar_msgs::masses masses_msg; - lidar_msgs::prediction prediction_msg; - int time=0; - bool data_acquired = false; - virtual void onInit(); - void timerCallback(const ros::TimerEvent&); - void createTensorFromFrames(tensorflow::Tensor& input); - void occupancy_grid_callback(const nav_msgs::OccupancyGrid::ConstPtr& occupancy); - void createPredictionAndPublish(std::vector& output); - void masses_callback(const lidar_msgs::masses::ConstPtr& masses_data); - void publishPrediction(); - void saveFrame(lidar_msgs::masses& data, int t); - void saveTensor(std::vector& output); - }; -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch.cpp deleted file mode 100644 index f98b3a3e2..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include -#include -#include -#include "inference_torch.h" - -#include -#include -#include -#include -#include -#include -#include -#include // One-stop header. - -#include -#include -#include - -#include -#include - -PLUGINLIB_EXPORT_CLASS(lidar_pkg::InferenceTorch, nodelet::Nodelet) - -using namespace std::chrono; - -namespace lidar_pkg -{ - void InferenceTorch::onInit() - { - ROS_INFO("Initialized PyTorch Inference."); - - if (torch::cuda::is_available()) - { - ROS_INFO("CUDA available! Inference on GPU."); - // device = torch::Device(torch::kCUDA); - } - else - { - ROS_INFO("Inference on CPU."); - // device = torch::Device(torch::kCPU); - } - - ros::NodeHandle &private_nh = getMTPrivateNodeHandle(); - - // Path to the model - std::string jitPath = "/home/bernard/catkin_ws/src/ROS_OGP/ROSOccupancyGridPrediction/models/prednet_with_taa.pt"; - - // Loading the model - ROS_INFO("Loading the module..."); - try - { - module = std::make_shared(torch::jit::load(jitPath)); - module->to(torch::kCUDA); - module->eval(); - torch::NoGradGuard no_grad; - // torch::Tensor input_data = torch::ones({1, 20, 2, 128, 128}); - // std::vector input; - // input.push_back(input_data.to(torch::kCUDA)); - // at::Tensor output = module->forward(input).toTensor(); - - // std::shared_ptr module = torch::jit::load(jitPath); - // module->to(torch::kCUDA); - } - catch (const c10::Error &e) - { - std::cerr << "error loading the model\n"; - // Something for errors - } - - ROS_INFO("Loaded!"); - - pred_pub = private_nh.advertise("prediction", 1); - pred_all_pub = private_nh.advertise("prediction_all", 1); - // occupancy_grid_sub = private_nh.subscribe("occupancy", 1, &InferenceTorch::occupancy_grid_callback, this); - masses_sub = private_nh.subscribe("masses", 1, &InferenceTorch::masses_callback, this); - timer = private_nh.createTimer(ros::Duration(0.001), &InferenceTorch::timerCallback, this); // Reduced time but it didn't change much - } - - void InferenceTorch::timerCallback(const ros::TimerEvent &) - { - auto start = high_resolution_clock::now(); - std::vector input; - if (data_acquired == true) - { - // ROS_INFO("Processing masses"); - createTensorFromFrames(input); - } - else - { - // Warm-up for LibTorch. First inference is slow - ROS_INFO("Not enough data..."); - torch::Tensor input_data = torch::ones({1, 20, 2, 128, 128}); - input.push_back(input_data.to(torch::kCUDA)); - } - auto stop1 = high_resolution_clock::now(); - // ROS_INFO("Making predictions"); - torch::Tensor output = Infer(input); - auto stop2 = high_resolution_clock::now(); - // ROS_INFO("Publishing the prediction"); - Publish(output); - auto stop3 = high_resolution_clock::now(); - auto duration1 = duration_cast(stop1 - start); - auto duration2 = duration_cast(stop2 - stop1); - auto duration3 = duration_cast(stop3 - stop2); - // std::cout << "Times: " << duration1.count() << " " << duration2.count() << " " << duration3.count() << std::endl; - } - - torch::Tensor InferenceTorch::Infer(const std::vector &input) - { - torch::NoGradGuard no_grad; - torch::Tensor output = module->forward(input).toTensor(); - // std::cout << "Device type: " << (output.device().type()) << std::endl; - // std::cout << "Required grad: " << (output.requires_grad()) << std::endl; - return output; - } - - void InferenceTorch::Publish(torch::Tensor &out) - { - prediction_msg.prediction.clear(); - torch::Device device(torch::kCPU); - torch::Tensor new_out = out.to(device); - - int grid_size = 128; - auto output_values = new_out.accessor(); - int probability; - - for (unsigned int t = 0; t < 20; t++) - { - occupancy_msg.data.clear(); - occupancy_msg.info.resolution = 1. / 3.; - occupancy_msg.info.width = grid_size; - occupancy_msg.info.height = grid_size; - for (unsigned int i = 0; i < grid_size; i++) - { - for (unsigned int j = 0; j < grid_size; j++) - { - // Modify this accordingly - probability = (int)(100 * (0.5 * output_values[0][t][0][i][j] + 0.5 * (1.0 - output_values[0][t][1][i][j]))); - occupancy_msg.data.push_back(probability); - } - } - prediction_msg.prediction.push_back(occupancy_msg); - } - pred_all_pub.publish(prediction_msg); - pred_pub.publish(occupancy_msg); - } - - void InferenceTorch::createTensorFromFrames(std::vector &input) - { - - bool past = true; - torch::Tensor input_data = torch::empty({1, 20, 2, 128, 128}); - auto input_map = input_data.accessor(); - lidar_msgs::masses data; - for (unsigned int t = 0; t < 20; t++) - { - if (t < 5) - { - data = history_m[t]; - } - else - { - past = false; - } - int count = 0; - - for (unsigned int x = 0; x < 128; x++) - { - for (unsigned int y = 0; y < 128; y++) - { - if (past == true) - { - input_map[0][t][0][x][y] = (float)data.occ[count]; - input_map[0][t][1][x][y] = (float)data.free[count]; - } - count++; - } - } - } - input.clear(); - input.push_back(input_data.to(torch::kCUDA)); - } - - void InferenceTorch::masses_callback(const lidar_msgs::masses::ConstPtr &masses_data) - { - time++; - nav_msgs::OccupancyGrid zeross; - // zeross.data = occupancy.data; - if (time <= 5) - { - history_m.push_back(*masses_data); - } - else - { - data_acquired = true; - for (unsigned int i = 0; i <= 3; i++) - { - history_m[i] = history_m[i + 1]; - } - history_m[4] = (*masses_data); - } - } -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch.h b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch.h deleted file mode 100644 index fce40cd23..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch.h +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include // One-stop header. - -#include -#include -#include - -typedef int DST_mass[128][128][3]; - -namespace lidar_pkg { - class InferenceTorch : public nodelet::Nodelet - { - public: - InferenceTorch(){}; - private: - ros::Publisher pred_pub; - ros::Publisher pred_all_pub; - ros::Subscriber occupancy_grid_sub; - ros::Subscriber masses_sub; - ros::Timer timer; - std::vector> history; - std::vector history_n; - std::vector history_m; - nav_msgs::OccupancyGrid occupancy_msg; - lidar_msgs::masses masses_msg; - lidar_msgs::prediction prediction_msg; - int time=0; - bool data_acquired = false; - - //torch::jit::script::Module module; - std::shared_ptr module; - //torch::Device device; - - virtual void onInit(); - void timerCallback(const ros::TimerEvent&); - void createTensorFromFrames(std::vector& input); - void occupancy_grid_callback(const nav_msgs::OccupancyGrid::ConstPtr& occupancy); - // void createPredictionAndPublish(std::vector& input); - void Publish(torch::Tensor& new_out); - torch::Tensor Infer(const std::vector& input); - void masses_callback(const lidar_msgs::masses::ConstPtr& masses_data); - void publishPrediction(); - }; -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch_test.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch_test.cpp deleted file mode 100644 index 30207ccc2..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/inference_torch_test.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include -#include -#include "inference_torch.h" -#include // One-stop header. - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -PLUGINLIB_EXPORT_CLASS(lidar_pkg::InferenceTorch, nodelet::Nodelet) - -namespace lidar_pkg -{ - void InferenceTorch::onInit() - { - ROS_INFO("Initialized PyTorch Inference."); - ros::NodeHandle& private_nh = getMTPrivateNodeHandle(); - - // Path to the model - std::string jitPath = "/home/bernard/catkin_ws/src/ROS_OGP/RealTimeEnvironmentPrediction/models/taa.pt"; - - // Loading the model - ROS_INFO("Loading the module..."); - torch::jit::script::Module module; - try { - module = torch::jit::load(jitPath); - } - catch (const c10::Error& e) { - std::cerr << "error loading the model\n"; - return -1; - } - - ROS_INFO("Loaded!") - - pred_pub = private_nh.advertise("prediction", 1); - pred_all_pub = private_nh.advertise("prediction_all", 1); - occupancy_grid_sub = private_nh.subscribe("occupancy", 1, &Inference::occupancy_grid_callback, this); - masses_sub = private_nh.subscribe("masses", 1, &Inference::masses_callback, this); - timer = private_nh.createTimer(ros::Duration(0.02), &Inference::timerCallback, this); - } - - void Inference::timerCallback(const ros::TimerEvent&) - { - if (data_acquired==true) - { - ROS_INFO("Inside the timer"); - - //DEFINE APPROPRAITE GLOBAL VARIABLES - - tensorflow::Tensor input(tensorflow::DT_FLOAT, tensorflow::TensorShape({1,20,128,128,2})); - std::vector output; - - // Create/Fill in a tensor. - - input = createTensorFromFrames(); - - // Make a prediction - - createPredictionAndPublish(input); - //saveTensor(output); - } - else { - ROS_INFO("Clock is paused..."); - } - } - - void Inference::createPredictionAndPublish(input) - { - ROS_INFO("Publishing"); - prediction_msg.prediction.clear(); - at::Tensor output = module.forward(inputs).toTensor(); - int grid_size = 128; - auto output_values = output[0].tensor(); - int probability; - - for (unsigned int t = 0; t < 20; t++){ - occupancy_msg.data.clear(); - occupancy_msg.info.resolution = 1./3.; - occupancy_msg.info.width = grid_size; - occupancy_msg.info.height = grid_size; - for (unsigned int i = 0; i < grid_size; i++){ - for (unsigned int j = 0; j < grid_size; j++){ - //Modify this accordingly - probability = (int)(100*(0.5*output_values(0,t,i,j,0)+0.5*(1.0 - output_values(0,t,i,j,1)))); - occupancy_msg.data.push_back(probability); - } - } - prediction_msg.prediction.push_back(occupancy_msg); - } - pred_all_pub.publish(prediction_msg); - pred_pub.publish(occupancy_msg); - } - - void Inference::saveTensor(std::vector& output) - { - // auto output_values = output[0].tensor(); - // for(unsigned int t=0;t<20;t++){ - // std::vector occ; - // std::vector free; - // - // for(unsigned int x=0;x<128;x++){ - // for(unsigned int y=0;y<128;y++){ - // occ.push_back(output_values(0,t,x,y,0)); - // free.push_back(output_values(0,t,x,y,1)); - // } - // } - // std::ofstream outfile_occ("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/prediction_occ"+std::to_string(t)+".txt"); - // for (const auto &e : occ) outfile_occ << e << "\n"; - // - // std::ofstream outfile_free("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/prediction_free"+std::to_string(t)+".txt"); - // for (const auto &e : free) outfile_free << e << "\n"; - // - // } - } - - void Inference::createTensorFromFrames() - { - std::vector input; - - - // MODIFY - using namespace::tensorflow::ops; - bool past = true; - auto input_map = input.tensor(); - lidar_msgs::masses data; - - for(unsigned int t = 0; t<20;t++){ - if (t<5){ - data = history_m[t]; - } - else { - past = false; - } - int count = 0; - for(unsigned int x = 0; x<128;x++){ - for(unsigned int y = 0; y<128;y++){ - if(past==true){ - input_map(0,t,x,y,0) = (float)data.occ[count]; //check the ordering + add depth. - input_map(0,t,x,y,1) = (float)data.free[count]; - } - count++; - } - } - } - return input - } - - void Inference::saveFrame(lidar_msgs::masses& data, int t) - { - // std::vector occ; - // occ = data.occ; - // std::vector free; - // free = data.free; - // std::ofstream outfile_occ("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/past_occ"+std::to_string(t)+".txt"); - // for (const auto &e : occ) outfile_occ << e << "\n"; - // - // std::ofstream outfile_free("/home/ford/catkin_ws/src/lidar/lidar_pkg/src/data/past_free"+std::to_string(t)+".txt"); - // for (const auto &e : free) outfile_free << e << "\n"; - - } - - void Inference::occupancy_grid_callback(const nav_msgs::OccupancyGrid::ConstPtr& occupancy) - { - ROS_INFO("Data collected"); - time++; - nav_msgs::OccupancyGrid zeross; - //zeross.data = occupancy.data; - if (time <= 5){ - history_n.push_back(*occupancy); - } - else { - data_acquired = true; - for (unsigned int i=0; i<=3; i++){ - history_n[i] = history_n[i+1]; - } - history_n[4]=(*occupancy); - } - ROS_INFO("Done with Data collected"); - } - - void Inference::masses_callback(const lidar_msgs::masses::ConstPtr& masses_data) - { - ROS_INFO("Data collected Masses"); - //time++; - nav_msgs::OccupancyGrid zeross; - //zeross.data = occupancy.data; - if (time <= 5){ - history_m.push_back(*masses_data); - } - else { - data_acquired = true; - for (unsigned int i=0; i<=3; i++){ - history_m[i] = history_m[i+1]; - } - history_m[4] = (*masses_data); - } - ROS_INFO("Done with Data collected"); - } -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/mrf_ground_seg.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/mrf_ground_seg.cpp deleted file mode 100644 index 9a4835940..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/mrf_ground_seg.cpp +++ /dev/null @@ -1,227 +0,0 @@ -#include -#include "mrf_ground_seg.h" - -PLUGINLIB_EXPORT_CLASS(lidar_pkg::MrfGroundSeg, nodelet::Nodelet) - -namespace lidar_pkg -{ - - void MrfGroundSeg::onInit() - { -#if __cplusplus == 201103L - std::cout << "C++11" << std::endl; -#else - std::cout << "C++" << std::endl; -#endif - - ros::NodeHandle &private_nh = getMTPrivateNodeHandle(); - - pub = private_nh.advertise("mrf_filtered_points", 1); - sub = private_nh.subscribe("agg_points", 1, &MrfGroundSeg::GroundSegMRFCallback, this); - } - - void MrfGroundSeg::GroundSegMRFCallback(const DDLPointCloud::ConstPtr &originalPC) - { - ROS_INFO("Points for the segmentation received."); - int start_s = clock(); - - /* Parameters that can be specified via class later. */ - - // Specify the vertical offset distance of the LiDAR from the ground (specified by system - e.g. KITTI). - float lidarZ = 0.0; - - // Maximum keep LiDAR square distance. - float maxKeep = 80.0; - - float s = 0.55; // 0.6; // 0.09 - float res = 0.4; - - /* Build the grid. */ - - // Initialize the filtered point cloud to be published. - DDLPointCloud filteredPC; - - // Set the message time stamp. - filteredPC.header.stamp = originalPC->header.stamp; - // std::cout << "time stamp" << filteredPC.header.stamp << endl; - - // Dereference the point cloud. - const DDLPointCloud &cloud(*originalPC); - - // cout << cloud.header.frame_id << endl; - - // Get number of points in point cloud. - int origPCSize = cloud.width; - - // Get the maximum x, y distance. - float maxXYCoord = maxKeep; - - // max( max(-1 * minPoint.x, maxPoint.x), max(-1 * minPoint.y, maxPoint.y)); - - size_t gridSize = int(2 * ceil((maxXYCoord) / res) + 1); - - vector grid[gridSize][gridSize]; - - // Get center coordinates of the grid. - int centerX = int(ceil(maxXYCoord / res)); - int centerY = int(ceil(maxXYCoord / res)); - - // Populate the grid with indices of points that fit into a particular cell. - for (int i = 0; i < origPCSize; i++) - { - DDLPointType point = cloud.points[i]; - - // Ensure within specified area, and not above a filtered height - if ((abs(point.x) <= maxXYCoord) && (abs(point.y) <= maxXYCoord) && (point.z <= 3.5)) - { - grid[int(centerX + round(point.x / res))][int(centerY + round(point.y / res))].push_back(i); - // cout << "Z value: " << point.z << endl; - } - } - - /* Perform MRF segmentation. */ - - // Initialize the hG array. - float hG[gridSize][gridSize]; - - // Initialize the grid segmentation (ground cells have a value of 1). - int gridSeg[gridSize][gridSize]; - fill(gridSeg[0], gridSeg[0] + gridSize * gridSize, 0); - - // Initialize the center coordinate of the 2D grid to ground according to the height of the - // LiDAR position on the vehicle. - hG[centerX][centerY] = -1 * lidarZ; - gridSeg[centerX][centerY] = 1; - - // Allocate space for two elements in the vector. - vector outerIndex; - outerIndex.resize(2); - - // Move radially outwards and perform the MRF segmentation. - for (int i = 1; i < int(ceil(maxXYCoord / res)) + 1; i++) - { - - // Generate the indices at the ith circle level from the center of the grid. - outerIndex[0] = -1 * i; - outerIndex[1] = i; - - /* vector outerIndex; - outerIndex.push_back(-1 * i); - outerIndex.push_back(i); */ - - for (int index : outerIndex) - { - for (int k = -1 * i; k < (i + 1); k++) - { - - // Index is the outer index (perimeter of circle) and k is possible inner indices - // in between the edges. - Indices currentCircle; - currentCircle.insert(pair(centerX + index, centerY + k)); - - // Add the mirror image of cells to the circle if not on the top or bottom row of the circle. - if (!((k == -1 * i) || (k == i))) - { - currentCircle.insert(pair(centerX + k, centerY + index)); - } - - // Go through the one or two stored cells right now. - for (pair const &indexPair : currentCircle) - { - - int x = indexPair.first; - int y = indexPair.second; - - // Compute the minimum and maximum z coordinates of each grid cell. - - // Initialize H to a very small value. - float H = -numeric_limits::infinity(); - // Initialize h to a very large value. - float h = numeric_limits::infinity(); - - if (!grid[x][y].empty()) - { - - const vector pcIndices = grid[x][y]; - - for (int j = 0; j < pcIndices.size(); j++) - { - H = max(cloud.points[pcIndices[j]].z, H); - h = min(cloud.points[pcIndices[j]].z, h); - } - } - - // Pay attention to what happens when there are no points in a grid cell? Will it work? - - // Compute hHatG: find max hG of neighbors. - float hHatG = -numeric_limits::infinity(); - - // Get the inner circle neighbors of the current cell. - - // The inner circle is one level down from the current circle. - int innerCircleIndex = i - 1; - - // Center the grid at (0, 0). - int xRelativeIndex = x - centerX; - int yRelativeIndex = y - centerY; - - // Loop through possible neighbor indices. - for (int m = -1; m < 2; m++) - { - for (int n = -1; n < 2; n++) - { - - int xRelativeNew = abs(xRelativeIndex + m); - int yRelativeNew = abs(yRelativeIndex + n); - - // Ensure index is actually on the inner circle. - if (((xRelativeNew == innerCircleIndex) && (yRelativeNew <= innerCircleIndex)) || ((yRelativeNew == innerCircleIndex) && (xRelativeNew <= innerCircleIndex))) - { - - // Compute the new hHatG. - float hGTemp = hG[x + m][y + n]; - hHatG = max(hGTemp, hHatG); - } - } - } - - // Update hG of current cell. - if ((H != -numeric_limits::infinity()) && (h != numeric_limits::infinity()) && - ((H - h) < s) && ((H - hHatG) < s)) - { - gridSeg[x][y] = 1; - hG[x][y] = H; - } - else - { - hG[x][y] = hHatG; - - // Add the cell's LiDAR points to the segmented (not ground) point cloud. - if (!grid[x][y].empty()) - { - - const vector pcIndices = grid[x][y]; - - for (int j = 0; j < grid[x][y].size(); j++) - { - filteredPC.points.push_back(cloud.points[pcIndices[j]]); - } - } - } - } - } - } - } - - int stop_s = clock(); - // cout << "Width of point cloud before: " << cloud.width << endl; - // cout << "Width of point cloud now: " << filteredPC.points.size() << endl; - // cout << "Elapsed time outside for-loop: " << (stop_s - start_s)/double(CLOCKS_PER_SEC)*1000 << endl << endl; - - /* Set the frame_id to "vehicle_ground_cartesian". */ - - /* Publish to ROS node. */ - filteredPC.header.frame_id = cloud.header.frame_id; - pub.publish(filteredPC); - } -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/mrf_ground_seg.h b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/mrf_ground_seg.h deleted file mode 100644 index e515b127e..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/mrf_ground_seg.h +++ /dev/null @@ -1,31 +0,0 @@ -#include "ros/ros.h" -#include -#include -#include -#include -#include -#include - -using namespace std; - -typedef lidar_msgs::PointXYZIDBS DDLPointType; -typedef pcl::PointCloud DDLPointCloud; -typedef set > Indices; - -using namespace std; - -namespace lidar_pkg { - - class MrfGroundSeg : public nodelet::Nodelet - { - public: - MrfGroundSeg(){}; - private: - - ros::Publisher pub; - ros::Subscriber sub; - - virtual void onInit(); - void GroundSegMRFCallback(const DDLPointCloud::ConstPtr& originalPC); - }; -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/occupancy_grid_generation.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/occupancy_grid_generation.cpp deleted file mode 100644 index 36316a33a..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/occupancy_grid_generation.cpp +++ /dev/null @@ -1,533 +0,0 @@ -#include -#include "occupancy_grid_generation.h" //"occupancy_grid_generation.h" -#include -#include -#include -#include -#include -#include -#include - -PLUGINLIB_EXPORT_CLASS(lidar_pkg::OccupancyGridGeneration, nodelet::Nodelet) - -namespace lidar_pkg -{ - - void OccupancyGridGeneration::onInit() - { - ROS_INFO("Occupancy Grid nodelet has been initialized."); - - //Setting up the nodelet. - ros::NodeHandle& private_nh = getMTPrivateNodeHandle(); - - //Advertising the topics published by this node. - occ_pub = private_nh.advertise("occupancy", 1000); - masses_pub = private_nh.advertise("masses", 1000); - - //Subscrbing to the required information. - - // Filtered occupancy grid. - sub_2 = private_nh.subscribe ("mrf_filtered_points", 1, &OccupancyGridGeneration::cloud_cb, this); - - // Ros time. Subscribes to vehilce location every 0.01s. - timer = private_nh.createTimer(ros::Duration(0.01), &OccupancyGridGeneration::timer_cb, this); - } - - void OccupancyGridGeneration::timer_cb(const ros::TimerEvent&) - { - /*Make sure the frames are correct here. - /world for old rosbags and /map for new ones. /map should be a global cs and /vehicle_cg_cartesian a local vehicle cg. - We are looking for the translation of the vehicle wrt the global cs. - */ - - // tf::TransformListener listener; - // tf::StampedTransform transform; - // - // while(true){ - // try{ - // listener.lookupTransform("/map", "/vehicle_ground_cartesian", ros::Time(0), transform); - // break; - // } - // catch (tf::TransformException ex){ - // ros::Duration(0.01).sleep(); - // continue; - // } - // } - // prev_vehicle_x = vehicle_x; - // prev_vehicle_y = vehicle_y; - // vehicle_x = transform.getOrigin().x(); - // vehicle_y = transform.getOrigin().y(); - - // Bernard: I don't need frames ????? Are you sure? - change_x = 0.0; // vehicle_x - prev_vehicle_x; - change_y = 0.0; // vehicle_y - prev_vehicle_y; - - } - - - void OccupancyGridGeneration::cloud_cb (const sensor_msgs::PointCloud2ConstPtr& cloud_msg) - { - /* - PC processing. - */ - - double centerpoint_x = 64; - double centerpoint_y = 64; - double xstart = -1; - double ystart = -1; - double xend = -1; - double yend = -1; - - // Converts the PCL ros message using pcl_conversions. - pcl::PointCloud cloud; - pcl::fromROSMsg(*cloud_msg, cloud); - - // 1. Convert new measurement into a DST grid. - create_DST_grid(cloud); - - x_new_low = change_x - 64 * res; - x_new_high = change_x + 64 * res; - y_new_low = change_y - 64 * res; - y_new_high = change_y + 64 * res; - - if(initialization_phase == false) { - if ((x_new_low >= x_old_low) && (x_old_high >= x_new_low)) { - xstart = x_new_low; - xend = x_old_high; - } - - if ((y_new_low >= y_old_low) && (y_old_high >= y_new_low)) { - ystart = y_new_low; - yend = y_old_high; - } - - if ((x_new_low < x_old_low) && (x_new_high >= x_old_low)) { - xstart = x_old_low; - xend = x_new_high; - } - - if ((y_new_low < y_old_low) && (y_new_high >= y_old_low)) { - ystart = y_old_low; - yend = y_new_high; - } - - if ((xstart != -1) && (ystart != -1)) { - - int indx_nl = find_nearest(grid_size, xstart, x_new_low, x_new_high, res); - int indx_nh = find_nearest(grid_size, xend, x_new_low, x_new_high, res); - int indy_nl = find_nearest(grid_size, ystart, y_new_low, y_new_high, res); - int indy_nh = find_nearest(grid_size, yend, y_new_low, y_new_high, res); - - int indx_ol = find_nearest(grid_size, xstart, x_old_low, x_old_high, res); - int indx_oh = find_nearest(grid_size, xend, x_old_low, x_old_high, res); - int indy_ol = find_nearest(grid_size, ystart, y_old_low, y_old_high, res); - int indy_oh = find_nearest(grid_size, yend, y_old_low, y_old_high, res); - - for (unsigned int i=0; i < indx_oh - indx_ol + 1; i++) { - for (unsigned int j=0; j < indy_oh - indy_ol + 1; j++) { - prev_free[indx_nl + i][indy_nl + j] = up_free[indx_ol + i][indy_ol + j]; - prev_occ[indx_nl + i][indy_nl + j] = up_occ[indx_ol + i][indy_ol + j]; - } - } - } - } - mass_update(); - get_mass(); - plotting(); - clear(); - - initialization_phase = false; - x_old_low = x_new_low; - x_old_high = x_new_high; - y_old_low = y_new_low; - y_old_high = y_new_high; - } - - void OccupancyGridGeneration::create_DST_grid(pcl::PointCloud& cloud) - { - /* - Generate the occupancy grid. - Works pretty well. - Further improvments/simplifications can be done, but it is not a priority now. - */ - - // ROS_INFO("Inside create DST grid"); - //1.Projects the pcl points onto the 2D-plane/occupancy grid. Performs ray tracing to identify visible spaces. - add_points_to_the_DST(cloud); - //2.Performs ray tracing to identify visible spaces to angles around a vehicle which are not represented in the PC or out of range. - add_free_spaces_to_the_DST(); - //3.Add an ego vehicle to our grid. - add_ego_vehicle_to_the_DST(); - } - - void OccupancyGridGeneration::add_points_to_the_DST(pcl::PointCloud& cloud) - { - for (size_t i = 0; i < cloud.points.size(); i++) - { - int x = (int)(cloud.points[i].x/res); - int y = (int)(cloud.points[i].y/res); - double z = cloud.points[i].z; - - //FIX: Quick hack for Ford dataset. - if ((-1)*z>0.5){ - continue; - } - - // Checks if the pcl point is within our grid range. - // TODO: Replace 64 with some grid size parameter set once. - if (x >= -64 && y>= -64 && x <= 63 && y <= 63) { - int angle; - - // Angles vector contains which angles from 0 deg to 360 deg have been represented. - // It is used to identify free spaces for angles not covered by PC or out of range points. - if (cloud.points[i].y > 0 && cloud.points[i].x < 0){ - angle = 180 - (int)(atan(std::abs(cloud.points[i].y)/std::abs(cloud.points[i].x))*180.0/3.14159265); - } - else if (cloud.points[i].y < 0 && cloud.points[i].x < 0){ - angle = 180 + (int)(atan(std::abs(cloud.points[i].y)/std::abs(cloud.points[i].x))*180.0/3.14159265); - } - else if (cloud.points[i].y < 0 && cloud.points[i].x > 0){ - angle = 360 - (int)(atan(std::abs(cloud.points[i].y)/std::abs(cloud.points[i].x))*180.0/3.14159265); - } - else{ - angle = (int)(atan(std::abs(cloud.points[i].y)/std::abs(cloud.points[i].x))*180.0/3.14159265); - } - - angles[angle] = true; - double slope = (double)(y)/(x); - - // We perform ray/point tracing from the origin to the point to identify the free space using Bresenham's line algorthim. - // It is a simple algorithm but does a job pretty well. - if (slope > 0 && slope <= 1 && x>0){ - ray_tracing_approximation_y_increment(0,0,x,y,1,1,false); - } - else if (slope > 1 && x>0){ - ray_tracing_approximation_x_increment(0,0,x,y,1,1,false); - } - else if (slope < 0 && slope >= -1 && x>0){ - ray_tracing_approximation_y_increment(0,0,x,(-1)*y,1,-1,false); - } - else if (slope < -1 && x>0){ - ray_tracing_approximation_x_increment(0,0,x,(-1)*y,1,-1,false); - } - else if (slope > 1 && x<0){ - ray_tracing_approximation_x_increment(0,0,(-1)*x,(-1)*y,-1,-1,false); - } - else if (slope > 0 && slope <= 1 && x<0){ - ray_tracing_approximation_y_increment(0,0,(-1)*x,(-1)*y,-1,-1,false); - } - else if (slope < 0 && slope >= -1 && x<0){ - ray_tracing_approximation_y_increment(0,0,(-1)*x,y,-1,1,false); - } - else if (slope < -1 && x<0){ - ray_tracing_approximation_x_increment(0,0,(-1)*x,y,-1,1,false); - } - } - } - } - - void OccupancyGridGeneration::add_free_spaces_to_the_DST() - { - double i = 0.0; - float ang = 0.0f; - - /* - TODO: It is a naive approach to fill the free spaces and it should be changed. - However, it is not the bottleneck right now. - I'll comment it/clean it tmr. - */ - for (unsigned int i = 0; i<3600;i++){ - ang = (i*0.1f); - //std::cout << ang << std::endl; - if (angles[(int)(ang)] == false){ - int x,y; - if (ang>0.0f && ang<=45.0f){ - x = 64; - y = (int)(tan(ang*PI/180.0f)*x); - } - else if (ang>45.0f && ang<90.0f){ - y = 64; - x = (int)(y/tan(ang*PI/180.0f)); - } - else if (ang>90.0f && ang<=135.0f){ - y = 64; - x = (int)(y/tan((ang-180.0f)*PI/180.0f)); - } - else if (ang>135.0f && ang<180.0f){ - x = -64; - y = (int)(tan((ang-180.0)*PI/180.0f)*x); - } - else if (ang>180.0f && ang<=225.0f){ - x = -64; - y = (int)(tan((ang-180.0f)*PI/180.0f)*x); - } - else if (ang>225.0f && ang<270.0f){ - y = -64; - x = (int)(y/tan((ang-180.0f)*PI/180.0f)); - } - else if (ang>270.0f && ang<= 315.0f){ - y = -64; - x = (int)(y/tan((ang-360.0f)*PI/180.0f)); - } - else if (ang>315.0f && ang<360.0f){ - x = 64; - y = (int)(tan((ang-360.0f)*PI/180.0f)*x); - } - else if (ang == 0.0f || ang == 360.0f){ - ray_tracing_horizontal(64); - continue; - } - else if (ang == 90.0f){ - ray_tracing_vertical(64); - continue; - } - else if (ang == 180.0f){ - ray_tracing_horizontal_n(-64); - continue; - } - else if (ang == 270.0f){ - ray_tracing_vertical_n(-64); - continue; - } - - if (x >= -64 && y>= -64 && x <= 64 && y <= 64) { - - double slope = (double)(y)/(x); - if (slope > 0 && slope <= 1 && x>0){ - ray_tracing_approximation_y_increment(0,0,x,y,1,1,true); - } - else if (slope > 1 && x>0){ - ray_tracing_approximation_x_increment(0,0,x,y,1,1,true); - } - else if (slope < 0 && slope >= -1 && x>0){ - ray_tracing_approximation_y_increment(0,0,x,(-1)*y,1,-1,true); - } - else if (slope < -1 && x>0){ - ray_tracing_approximation_x_increment(0,0,x,(-1)*y,1,-1,true); - } - else if (slope > 1 && x<0){ - ray_tracing_approximation_x_increment(0,0,(-1)*x,(-1)*y,-1,-1,true); - } - else if (slope > 0 && slope <= 1 && x<0){ - ray_tracing_approximation_y_increment(0,0,(-1)*x,(-1)*y,-1,-1,true); - } - else if (slope < 0 && slope >= -1 && x<0){ - ray_tracing_approximation_y_increment(0,0,(-1)*x,y,-1,1,true); - } - else if (slope < -1 && x<0){ - ray_tracing_approximation_x_increment(0,0,(-1)*x,y,-1,1,true); - } - } - } - angles[(int)(ang)] = false; - } - } - - void OccupancyGridGeneration::add_ego_vehicle_to_the_DST() - { - // Vehicle shape. - for(unsigned int j = 60;j<68;j++){ - for(unsigned int i = 62;i<67;i++){ - meas_occ[j][i] = 1.0; - meas_free[j][i] = 0.0; - } - } - } - - void OccupancyGridGeneration::plotting() - { - occupancy_msg.data.clear(); - masses_msg.occ.clear(); - masses_msg.free.clear(); - occupancy_msg.header.frame_id = "/body"; //TODO: Make sure the frame is the correct one. - occupancy_msg.info.resolution = res; - occupancy_msg.info.width = grid_size; - occupancy_msg.info.height = grid_size; - occupancy_msg.info.origin.position.z = 0.2; - occupancy_msg.info.origin.position.x = -64.0*(1./3.); - occupancy_msg.info.origin.position.y = -64.0*(1./3.); - masses_msg.width = grid_size; - masses_msg.height = grid_size; - - for (unsigned int i = 0; i < grid_size; i++){ - for (unsigned int j = 0; j < grid_size; j++){ - occupancy_msg.data.push_back(prob_O_plot[j][i]); - masses_msg.occ.push_back(up_occ[j][i]); - masses_msg.free.push_back(up_free[j][i]); - } - } - occ_pub.publish(occupancy_msg); - masses_pub.publish(masses_msg); - } - - void OccupancyGridGeneration::mass_update() - { - for (unsigned int i = 0; i < grid_size; i++){ - for (unsigned int j = 0; j < grid_size; j++){ - up_occ_pred[i][j] = std::min(alpha * prev_occ[i][j], 1.0 - prev_free[i][j]); - up_free_pred[i][j] = std::min(alpha * prev_free[i][j], 1.0 - prev_occ[i][j]); - } - } - //Combine measurement nad prediction to form posterior occupied and free masses. - update_of(); - } - - void OccupancyGridGeneration::update_of() - { - for (unsigned int i = 0; i < grid_size; i++){ - for (unsigned int j = 0; j < grid_size; j++){ - double unknown_pred = 1.0 - up_free_pred[i][j] - up_occ_pred[i][j]; - double meas_cell_unknown = 1.0 - meas_free[i][j] - meas_occ[i][j]; - double k_value = up_free_pred[i][j] * meas_occ[i][j] + up_occ_pred[i][j] * meas_free[i][j]; - up_occ[i][j] = (up_occ_pred[i][j] * meas_cell_unknown + unknown_pred * meas_occ[i][j] + up_occ_pred[i][j] * meas_occ[i][j])/ (1.0 - k_value); - up_free[i][j] = (up_free_pred[i][j] * meas_cell_unknown + unknown_pred * meas_free[i][j] + up_free_pred[i][j] * meas_free[i][j])/ (1.0 - k_value); - } - } - } - - void OccupancyGridGeneration::get_mass() - { - for (unsigned int i = 0; i < grid_size; i++){ - for (unsigned int j = 0; j < grid_size; j++){ - prob_O[i][j] = (0.5 * up_occ[i][j] + 0.5*(1.0 - up_free[i][j])); - prob_O_plot[i][j] = 100*(0.5 * up_occ[i][j] + 0.5*(1.0 - up_free[i][j])); //meas_occ[i][j] * 100; - } - } - } - - int OccupancyGridGeneration::find_nearest(int n, double v, double v0, double vn, double res) - { - int idx = std::floor(n*(v-v0+res/2.)/(vn-v0+res)); - return idx; - } - - - void OccupancyGridGeneration::ray_tracing_approximation_y_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive) - { - int slope = 2 * (y2 - y1); - int slope_error = slope - (x2 - x1); - int x_sample, y_sample; - for (int x = x1, y = y1; x < x2; x++){ - if (meas_occ[flip_x*x+64][flip_y*y+64] == meas_mass) { - break; - } - - meas_free[flip_x*x+64][flip_y*y+64] = meas_mass; - - slope_error += slope; - if (slope_error >= 0) { - y += 1; - slope_error -= 2 * (x2 - x1); - } - } - - if (inclusive==false) { - meas_occ[flip_x*x2+64][flip_y*y2+64] = meas_mass; - meas_free[flip_x*x2+64][flip_y*y2+64] = 0.0; - } - } - - void OccupancyGridGeneration::ray_tracing_approximation_x_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive) - { - int slope = 2 * (x2 - x1); - int slope_error = slope - (y2 - y1); - int x_sample, y_sample; - for (int x = x1, y = y1; y < y2; y++){ - - if (meas_occ[flip_x*x+64][flip_y*y+64] == meas_mass) { - break; - } - - meas_free[flip_x*x+64][flip_y*y+64] = meas_mass; - - slope_error += slope; - if (slope_error >= 0) { - x += 1; - slope_error -= 2 * (y2 - y1); - } - } - - if (inclusive==false) { - meas_occ[flip_x*x2+64][flip_y*y2+64] = meas_mass; - meas_free[flip_x*x2+64][flip_y*y2+64] = 0.0; - } - } - - void OccupancyGridGeneration::ray_tracing_horizontal(int x2) - { - int x1 = 0; - int y1 = 0; - x2 = x2 - 1; - - for (int x = x1; x <= x2; x++){ - - if (meas_occ[x+64][64] == meas_mass) { - break; - } - - meas_free[x+64][64] = meas_mass; - } - - meas_free[x2+64][64] = 0.0; - } - - void OccupancyGridGeneration::ray_tracing_horizontal_n(int x1) - { - int x2 = 0; - int y2 = 0; - x1 = x1+1; - - for (int x = x1; x <= x2; x++){ - - if (meas_occ[x+64][64] == meas_mass) { - break; - } - - meas_free[x+64][64] = meas_mass; - } - - meas_free[x2+64][64] = 0.0; - } - - void OccupancyGridGeneration::ray_tracing_vertical(int y2) - { - int x1 = 0; - int y1 = 0; - y2 = y2-1; - - for (int y = y1; y <= y2; y++){ - - if (meas_occ[64][y+64] == meas_mass) { - break; - } - meas_free[64][y+64] = meas_mass; - } - } - - void OccupancyGridGeneration::ray_tracing_vertical_n(int y1) - { - int x1 = 0; - int y2 = 0; - y1 = y1+1; - - for (int y = y1; y <= y2; y++){ - - if (meas_occ[64][y+64] == meas_mass) { - break; - } - meas_free[64][y+64] = meas_mass; - } - - meas_free[64][y2+64] = 0.0; - } - - void OccupancyGridGeneration::clear() - { - for (unsigned int i =0; i -#include -#include -#include -#include -#include -#include -#include -#include - -typedef lidar_msgs::PointXYZIDBS DDLPointType; - -#define PI 3.14159 - -/* -TODO:BERNARD -Write a documentation/Comment. -*/ - - -namespace lidar_pkg -{ -class OccupancyGridGeneration : public nodelet::Nodelet -{ -public: - OccupancyGridGeneration(){}; -private: - - bool initialization_phase = true; - double vehicle_x; - double vehicle_y; - double prev_vehicle_x; - double prev_vehicle_y; - double change_x; - double change_y; - double x_new_low; - double x_new_high; - double y_new_low; - double y_new_high; - double x_old_low; - double x_old_high; - double y_old_low; - double y_old_high; - - // There are only two events: 0 = Occupied and 1 = Free. - const static int event_num = 2; - - // Grid size. - const static int grid_size = 128; - - // Resolution. - constexpr static double res = 1./3.; - - // Measurement mass. - constexpr static double meas_mass = 0.95; - - // Occupancy measurement. - constexpr static double alpha = 0.9; - - // Place holders vehicle positions. - constexpr static double vehicle_pos_x = 0; - constexpr static double vehicle_pos_y = 0; - constexpr static double prev_vehicle_pos_x = 0; - constexpr static double prev_vehicle_pos_y = 0; - - ros::Subscriber sub_2; - ros::Timer timer; - ros::Publisher occ_pub; - ros::Publisher masses_pub; - nav_msgs::OccupancyGrid occupancy_msg; - lidar_msgs::masses masses_msg; - - // Array with the DST data. - double meas_grids[event_num][grid_size][grid_size]; - - // "Freeness" measurement. - double meas_free[grid_size][grid_size] = {{0}}; - - // Occupancy measurement. - double meas_occ[grid_size][grid_size] = {{0}}; - double prev_free[grid_size][grid_size] = {{0}}; - double prev_occ[grid_size][grid_size] = {{0}}; - double up_free_pred[grid_size][grid_size]; - double up_occ_pred[grid_size][grid_size]; - double up_free[grid_size][grid_size]; - double up_occ[grid_size][grid_size]; - double prob_O[grid_size][grid_size]; - double prob_O_plot[grid_size][grid_size]; - bool angles[360]; - bool first; - - virtual void onInit(); - void timer_cb(const ros::TimerEvent&); - - void transform_listener(); - void cloud_cb(const sensor_msgs::PointCloud2ConstPtr& cloud_msg); - void create_DST_grid(pcl::PointCloud& cloud); - void ray_tracing_approximation_x_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive); - void ray_tracing_approximation_y_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive); - int find_nearest(int n, double v, double v0, double vn, double res); - void mass_update(); - void update_of(); - void get_mass(); - void plotting(); - void clear(); - void fill(std::vector flip); - void ray_tracing_horizontal(int y); - void ray_tracing_horizontal_n(int y); - void ray_tracing_vertical(int x); - void ray_tracing_vertical_n(int x); - void add_points_to_the_DST(pcl::PointCloud& cloud); - void add_free_spaces_to_the_DST(); - void add_ego_vehicle_to_the_DST(); -}; -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/utils.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/utils.cpp deleted file mode 100644 index 950a3f984..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/utils.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include -#include -#include - -#include "tensorflow/cc/ops/const_op.h" -#include "tensorflow/cc/ops/image_ops.h" -#include "tensorflow/cc/ops/standard_ops.h" -#include "tensorflow/core/framework/graph.pb.h" -#include "tensorflow/core/framework/tensor.h" -#include "tensorflow/core/graph/default_device.h" -#include "tensorflow/core/graph/graph_def_builder.h" -#include "tensorflow/core/lib/core/errors.h" -#include "tensorflow/core/lib/core/stringpiece.h" -#include "tensorflow/core/lib/core/threadpool.h" -#include "tensorflow/core/lib/io/path.h" -#include "tensorflow/core/lib/strings/stringprintf.h" -#include "tensorflow/core/platform/env.h" -#include "tensorflow/core/platform/init_main.h" -#include "tensorflow/core/platform/logging.h" -#include "tensorflow/core/platform/types.h" -#include "tensorflow/core/public/session.h" -#include "tensorflow/core/util/command_line_flags.h" - -// #include -#include -#include - -using namespace std; -using namespace cv; - -using tensorflow::Flag; -using tensorflow::Tensor; -using tensorflow::Status; -using tensorflow::string; -using tensorflow::int32; - -/** Read a model graph definition (xxx.pb) from disk, and creates a session object you can use to run it. - */ -Status loadGraph(const string &graph_file_name, - unique_ptr *session) { - tensorflow::GraphDef graph_def; - Status load_graph_status = - ReadBinaryProto(tensorflow::Env::Default(), graph_file_name, &graph_def); - if (!load_graph_status.ok()) { - std::cout << graph_file_name << std::endl; - std::cout << "NOT LOADING" << std::endl; - std::cout << tensorflow::errors::NotFound("Failed to load compute graph at '", - graph_file_name, "'") <reset(tensorflow::NewSession(tensorflow::SessionOptions())); - Status session_create_status = (*session)->Create(graph_def); - if (!session_create_status.ok()) { - return session_create_status; - } - return Status::OK(); -} - -/** Read a labels map file (xxx.pbtxt) from disk to translate class numbers into human-readable labels. - */ -// Status readLabelsMapFile(const string &fileName, map &labelsMap) { -// -// // Read file into a string -// ifstream t(fileName); -// if (t.bad()) -// return tensorflow::errors::NotFound("Failed to load labels map at '", fileName, "'"); -// stringstream buffer; -// buffer << t.rdbuf(); -// string fileString = buffer.str(); -// -// // Search entry patterns of type 'item { ... }' and parse each of them -// smatch matcherEntry; -// smatch matcherId; -// smatch matcherName; -// const regex reEntry("item \\{([\\S\\s]*?)\\}"); -// const regex reId("[0-9]+"); -// const regex reName("\'.+\'"); -// string entry; -// -// auto stringBegin = sregex_iterator(fileString.begin(), fileString.end(), reEntry); -// auto stringEnd = sregex_iterator(); -// -// int id; -// string name; -// for (sregex_iterator i = stringBegin; i != stringEnd; i++) { -// matcherEntry = *i; -// entry = matcherEntry.str(); -// regex_search(entry, matcherId, reId); -// if (!matcherId.empty()) -// id = stoi(matcherId[0].str()); -// else -// continue; -// regex_search(entry, matcherName, reName); -// if (!matcherName.empty()) -// name = matcherName[0].str().substr(1, matcherName[0].str().length() - 2); -// else -// continue; -// labelsMap.insert(pair(id, name)); -// } -// return Status::OK(); -// } -// -// /** Convert Mat image into tensor of shape (1, height, width, d) where last three dims are equal to the original dims. -// */ -// Status readTensorFromMat(const Mat &mat, Tensor &outTensor) { -// -// auto root = tensorflow::Scope::NewRootScope(); -// using namespace ::tensorflow::ops; -// -// // Trick from https://github.com/tensorflow/tensorflow/issues/8033 -// float *p = outTensor.flat().data(); -// Mat fakeMat(mat.rows, mat.cols, CV_32FC3, p); -// mat.convertTo(fakeMat, CV_32FC3); -// -// auto input_tensor = Placeholder(root.WithOpName("input"), tensorflow::DT_FLOAT); -// vector> inputs = {{"input", outTensor}}; -// auto uint8Caster = Cast(root.WithOpName("uint8_Cast"), outTensor, tensorflow::DT_UINT8); -// -// // This runs the GraphDef network definition that we've just constructed, and -// // returns the results in the output outTensor. -// tensorflow::GraphDef graph; -// TF_RETURN_IF_ERROR(root.ToGraphDef(&graph)); -// -// vector outTensors; -// unique_ptr session(tensorflow::NewSession(tensorflow::SessionOptions())); -// -// TF_RETURN_IF_ERROR(session->Create(graph)); -// TF_RETURN_IF_ERROR(session->Run({inputs}, {"uint8_Cast"}, {}, &outTensors)); -// -// outTensor = outTensors.at(0); -// return Status::OK(); -// } -// -// /** Draw bounding box and add caption to the image. -// * Boolean flag _scaled_ shows if the passed coordinates are in relative units (true by default in tensorflow detection) -// */ -// void drawBoundingBoxOnImage(Mat &image, double yMin, double xMin, double yMax, double xMax, double score, string label, bool scaled=true) { -// cv::Point tl, br; -// if (scaled) { -// tl = cv::Point((int) (xMin * image.cols), (int) (yMin * image.rows)); -// br = cv::Point((int) (xMax * image.cols), (int) (yMax * image.rows)); -// } else { -// tl = cv::Point((int) xMin, (int) yMin); -// br = cv::Point((int) xMax, (int) yMax); -// } -// cv::rectangle(image, tl, br, cv::Scalar(0, 255, 255), 1); -// -// // Ceiling the score down to 3 decimals (weird!) -// float scoreRounded = floorf(score * 1000) / 1000; -// string scoreString = to_string(scoreRounded).substr(0, 5); -// string caption = label + " (" + scoreString + ")"; -// -// // Adding caption of type "LABEL (X.XXX)" to the top-left corner of the bounding box -// int fontCoeff = 12; -// cv::Point brRect = cv::Point(tl.x + caption.length() * fontCoeff / 1.6, tl.y + fontCoeff); -// cv::rectangle(image, tl, brRect, cv::Scalar(0, 255, 255), -1); -// cv::Point textCorner = cv::Point(tl.x, tl.y + fontCoeff * 0.9); -// cv::putText(image, caption, textCorner, FONT_HERSHEY_SIMPLEX, 0.4, cv::Scalar(255, 0, 0)); -// } -// -// /** Draw bounding boxes and add captions to the image. -// * Box is drawn only if corresponding score is higher than the _threshold_. -// */ -// void drawBoundingBoxesOnImage(Mat &image, -// tensorflow::TTypes::Flat &scores, -// tensorflow::TTypes::Flat &classes, -// tensorflow::TTypes::Tensor &boxes, -// map &labelsMap, -// vector &idxs) { -// for (int j = 0; j < idxs.size(); j++) -// drawBoundingBoxOnImage(image, -// boxes(0,idxs.at(j),0), boxes(0,idxs.at(j),1), -// boxes(0,idxs.at(j),2), boxes(0,idxs.at(j),3), -// scores(idxs.at(j)), labelsMap[classes(idxs.at(j))]); -// } -// -// /** Calculate intersection-over-union (IOU) for two given bbox Rects. -// */ -// double IOU(Rect2f box1, Rect2f box2) { -// -// float xA = max(box1.tl().x, box2.tl().x); -// float yA = max(box1.tl().y, box2.tl().y); -// float xB = min(box1.br().x, box2.br().x); -// float yB = min(box1.br().y, box2.br().y); -// -// float intersectArea = abs((xB - xA) * (yB - yA)); -// float unionArea = abs(box1.area()) + abs(box2.area()) - intersectArea; -// -// return 1. * intersectArea / unionArea; -// } -// -// /** Return idxs of good boxes (ones with highest confidence score (>= thresholdScore) -// * and IOU <= thresholdIOU with others). -// */ -// vector filterBoxes(tensorflow::TTypes::Flat &scores, -// tensorflow::TTypes::Tensor &boxes, -// double thresholdIOU, double thresholdScore) { -// -// vector sortIdxs(scores.size()); -// iota(sortIdxs.begin(), sortIdxs.end(), 0); -// -// // Create set of "bad" idxs -// set badIdxs = set(); -// size_t i = 0; -// while (i < sortIdxs.size()) { -// if (scores(sortIdxs.at(i)) < thresholdScore) -// badIdxs.insert(sortIdxs[i]); -// if (badIdxs.find(sortIdxs.at(i)) != badIdxs.end()) { -// i++; -// continue; -// } -// -// Rect2f box1 = Rect2f(Point2f(boxes(0, sortIdxs.at(i), 1), boxes(0, sortIdxs.at(i), 0)), -// Point2f(boxes(0, sortIdxs.at(i), 3), boxes(0, sortIdxs.at(i), 2))); -// for (size_t j = i + 1; j < sortIdxs.size(); j++) { -// if (scores(sortIdxs.at(j)) < thresholdScore) { -// badIdxs.insert(sortIdxs[j]); -// continue; -// } -// Rect2f box2 = Rect2f(Point2f(boxes(0, sortIdxs.at(j), 1), boxes(0, sortIdxs.at(j), 0)), -// Point2f(boxes(0, sortIdxs.at(j), 3), boxes(0, sortIdxs.at(j), 2))); -// if (IOU(box1, box2) > thresholdIOU) -// badIdxs.insert(sortIdxs[j]); -// } -// i++; -// } -// -// // Prepare "good" idxs for return -// vector goodIdxs = vector(); -// for (auto it = sortIdxs.begin(); it != sortIdxs.end(); it++) -// if (badIdxs.find(sortIdxs.at(*it)) == badIdxs.end()) -// goodIdxs.push_back(*it); -// -// return goodIdxs; -// } diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/utils.h b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/utils.h deleted file mode 100644 index 026779028..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/utils.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TF_DETECTOR_EXAMPLE_UTILS_H -#define TF_DETECTOR_EXAMPLE_UTILS_H - -#endif //TF_DETECTOR_EXAMPLE_UTILS_H - -#include -#include "tensorflow/core/framework/tensor.h" -#include "tensorflow/core/public/session.h" -#include - - -using tensorflow::Tensor; -using tensorflow::Status; -using tensorflow::string; - - -Status readLabelsMapFile(const string &fileName, std::map &labelsMap); - -Status loadGraph(const string &graph_file_name, - std::unique_ptr *session); - -Status readTensorFromMat(const cv::Mat &mat, Tensor &outTensor); - -void drawBoundingBoxOnImage(cv::Mat &image, double xMin, double yMin, double xMax, double yMax, double score, std::string label, bool scaled); - -void drawBoundingBoxesOnImage(cv::Mat &image, - tensorflow::TTypes::Flat &scores, - tensorflow::TTypes::Flat &classes, - tensorflow::TTypes::Tensor &boxes, - std::map &labelsMap, - std::vector &idxs); - -double IOU(cv::Rect box1, cv::Rect box2); - -std::vector filterBoxes(tensorflow::TTypes::Flat &scores, - tensorflow::TTypes::Tensor &boxes, - double thresholdIOU, double thresholdScore); diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/visualize.cpp b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/visualize.cpp deleted file mode 100644 index 202461d47..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/visualize.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include -#include -#include -#include "visualize.h" - -PLUGINLIB_EXPORT_CLASS(lidar_pkg::Visualize, nodelet::Nodelet) - -namespace lidar_pkg -{ - void Visualize::onInit() - { - ROS_INFO("Initialized visualization."); - ros::NodeHandle &private_nh = getMTPrivateNodeHandle(); - visualization_pub = private_nh.advertise("visualization", 1); - prediction_sub = private_nh.subscribe("prediction_all", 1, &Visualize::prediction_callback, this); - timer = private_nh.createTimer(ros::Duration(0.1), &Visualize::timerCallback, this); // What time? Should it matter? - } - - void Visualize::prediction_callback(const lidar_msgs::prediction::ConstPtr &msg) - { - newest_prediction = *msg; - data_acquired = true; - lasttime = ros::Time::now(); - count++; - } - - void Visualize::timerCallback(const ros::TimerEvent &) - { - ROS_INFO("VISUAL"); - int count1 = count; - ros::Time currenttime = ros::Time::now(); - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - ros::Time currenttime2 = ros::Time::now(); - int count2 = count; - while (true) - { - if (data_acquired == true) - { - ROS_INFO("PRED"); - ros::Duration d(0.2); - double gap = d.toSec(); - int grid_size = 128; - occupancy_msg.header.frame_id = "/body"; - occupancy_msg.info.resolution = 1. / 3.; - occupancy_msg.info.width = grid_size; - occupancy_msg.info.height = grid_size; - occupancy_msg.info.origin.position.x = 64.0 * (1. / 3.); - occupancy_msg.info.origin.position.y = -64.0 * (1. / 3.); - - for (unsigned int t = 4; t < 20; t++) - { - occupancy_msg.data.clear(); - if (currenttime == currenttime2) - { // count1 == count2 - // ROS_INFO("PAUSE"); - - int count_grid = 0; - for (unsigned int i = 0; i < 128; i++) - { - for (unsigned int j = 0; j < 128; j++) - { - occupancy_msg.data.push_back(newest_prediction.prediction[t].data[count_grid]); - count_grid++; - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - } - else - { - // ROS_INFO("NO PAUSE"); - for (unsigned int i = 0; i < 128 * 128; i++) - { - occupancy_msg.data.push_back(0.0); - } - } - visualization_pub.publish(occupancy_msg); - } - } - break; - } - } -} diff --git a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/visualize.h b/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/visualize.h deleted file mode 100644 index 8a1f19e1b..000000000 --- a/src/perception/ROSOccupancyGridPrediction/lidar_pkg/src/visualize.h +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include -#include -#include -#include -#include - -namespace lidar_pkg { - - class Visualize : public nodelet::Nodelet - { - public: - Visualize(){}; - private: - ros::Publisher visualization_pub; - ros::Subscriber prediction_sub; - ros::Timer timer; - nav_msgs::OccupancyGrid occupancy_msg; - lidar_msgs::prediction newest_prediction; - ros::Time lasttime; - int count = 0; - bool data_acquired = false; - virtual void onInit(); - void timerCallback(const ros::TimerEvent&); - void prediction_callback(const lidar_msgs::prediction::ConstPtr& msg); - void saveFrame(std::vector data, int t); - }; -} diff --git a/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/CMakeLists.txt b/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/CMakeLists.txt deleted file mode 100644 index 53195b19b..000000000 --- a/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -project(pcl_tf_frame) -find_package(catkin REQUIRED COMPONENTS roscpp tf2 tf2_ros) -catkin_package() -include_directories(${catkin_INCLUDE_DIRS}) -add_executable(frame_broadcaster src/frame_broadcaster.cpp) -target_link_libraries(frame_broadcaster ${catkin_LIBRARIES}) diff --git a/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/package.xml b/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/package.xml deleted file mode 100644 index 51c40d709..000000000 --- a/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/package.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - pcl_tf_frame - 0.0.0 - The pcl_tf_frame package - - - - - bernard - - - - - - TODO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - catkin - - - - - - - - diff --git a/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/src/frame_broadcaster.cpp b/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/src/frame_broadcaster.cpp deleted file mode 100644 index 8829b19e1..000000000 --- a/src/perception/ROSOccupancyGridPrediction/pcl_tf_frame/src/frame_broadcaster.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -int main(int argc, char** argv){ - ros::init(argc, argv, "my_tf2_broadcaster"); - ros::NodeHandle node; - - tf2_ros::TransformBroadcaster tfb; - geometry_msgs::TransformStamped transformStamped; - - - transformStamped.header.frame_id = "body"; - transformStamped.child_frame_id = "global_pcl_frame"; - transformStamped.transform.translation.x = 0.0; - transformStamped.transform.translation.y = 0.0; - transformStamped.transform.translation.z = 0.0; - double pi = 3.14159; - tf2::Quaternion q; - q.setRPY(1*pi, 0, 0); // Roll-Pitch-Yaw: rotation about x->y->z in that order - transformStamped.transform.rotation.x = q.x(); - transformStamped.transform.rotation.y = q.y(); - transformStamped.transform.rotation.z = q.z(); - transformStamped.transform.rotation.w = q.w(); - - ros::Rate rate(10.0); - while (node.ok()){ - transformStamped.header.stamp = ros::Time::now(); - tfb.sendTransform(transformStamped); - rate.sleep(); - // printf("sending\n"); - } - -}; diff --git a/src/perception/dynamic_grid/dynamic_grid/dynamic_grid_node.py b/src/perception/dynamic_grid/dynamic_grid/dynamic_grid_node.py deleted file mode 100644 index 237b0246c..000000000 --- a/src/perception/dynamic_grid/dynamic_grid/dynamic_grid_node.py +++ /dev/null @@ -1,360 +0,0 @@ -import numpy as np -import pickle -import sys -import os -import math -#from shadowcasting import ShadowCaster -from rosgraph_msgs.msg import Clock - -import rclpy -from rclpy.node import Node -import ros2_numpy as rnp -from sensor_msgs.msg import PointCloud2 -from std_msgs.msg import String -from nav_msgs.msg import OccupancyGrid, MapMetaData -from nova_msgs.msg import StaticGrid -from nova_msgs.msg import GridRow - - - -class ShadowCaster: - - def __init__(self, mapwidth, mapheight): - self.width = mapwidth - self.height = mapheight - self.visiblemap = [] - self.seethrough = [] - self.sourcex = 0 - self.sourcey = 0 - self.range = 0 - - def cast_shadow(self, seethrough, sourcex, sourcey, sightrange): - self.sourcex = sourcex - self.sourcey = sourcey - self.range = sightrange - self.seethrough = seethrough - self.visiblemap = [[False for y in range(self.height)] - for x in range(self.width)] - self.visiblemap[sourcex][sourcey] = True - for octant in range(1, 9): - self._scan(1, octant, 1.0, 0.0) - return self.visiblemap - - def _scan(self, depth, octant, startslope, endslope): - x = 0 - y = 0 - if octant == 1: # NW - x = self.sourcex - int(startslope * depth) - y = self.sourcey - depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x - 1, y, False): - startslope = self._get_slope(x - .5, y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x - 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x - .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x += 1 - x -= 1 - elif octant == 2: # NE - x = self.sourcex + int(startslope * depth) - y = self.sourcey - depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x + 1, y, False): - startslope = -self._get_slope(x + .5, y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x + 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x + .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x -= 1 - x += 1 - elif octant == 3: # EN - x = self.sourcex + depth - y = self.sourcey - int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y - 1, False): - startslope = -self._get_inv_slope(x + .5, - y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y - 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x - .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y += 1 - y -= 1 - elif octant == 4: # ES - x = self.sourcex + depth - y = self.sourcey + int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y + 1, False): - startslope = self._get_inv_slope(x + .5, - y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y + 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x - .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y -= 1 - y += 1 - elif octant == 5: # SE - x = self.sourcex + int(startslope * depth) - y = self.sourcey + depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x + 1, y, False): - startslope = self._get_slope(x + .5, y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x + 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x + .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x -= 1 - x += 1 - elif octant == 6: # SW - x = self.sourcex - int(startslope * depth) - y = self.sourcey + depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x - 1, y, False): - startslope = -self._get_slope(x - .5, y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x - 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x - .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x += 1 - x -= 1 - elif octant == 7: # WS - x = self.sourcex - depth - y = self.sourcey + int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y + 1, False): - startslope = -self._get_inv_slope(x - .5, - y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y + 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x + .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y -= 1 - y += 1 - elif octant == 8: # WN - x = self.sourcex - depth - y = self.sourcey - int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y - 1, False): - startslope = self._get_inv_slope(x - .5, - y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y - 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x + .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y += 1 - y -= 1 - if x < 0: - x = 0 - if x >= self.width: - x = self.width - 1 - if y < 0: - y = 0 - if y >= self.height: - y = self.height - 1 - if self._is_visible(x, y) and self.seethrough[x][y]: - self._scan(depth + 1, octant, startslope, endslope) - - def _check_bounds(self, x, y): - if x < 0 or y < 0 or x >= self.width or y >= self.height: - return False - else: - return True - - def _get_slope(self, x1, y1, x2, y2): - return float(x1 - x2) / float(y1 - y2) - - def _get_inv_slope(self, x1, y1, x2, y2): - return float(y1 - y2) / float(x1 - x2) - - def _is_visible(self, x, y): - if self._check_bounds(self.sourcex, self.sourcey) and \ - self._check_bounds(x, y): - return math.hypot(self.sourcex - x, self.sourcey - y) <= self.range - else: - return False - - def _test_tile(self, x, y, state): - if not self._is_visible(x, y): - return False - else: - return self.seethrough[x][y] == state - - -class DynamicGridNode(Node): - def __init__(self): - super().__init__('dynamic_grid_node') - self.get_logger().info('#####################################################################################') - self.dynamic_grid = [] - self.RESULT_PATH = './' - self.point_cloud_sub = self.create_subscription(PointCloud2, '/lidar_filtered', self.create_grid, 10) - - self.grid_pub = self.create_publisher(OccupancyGrid, 'static_grid', 10) - - #self.point_cloud_pub = self.create_publisher(PointCloud2, 'ground_seg_points', 10) - - - def create_grid(self, point_cloud: PointCloud2): - - #df = pd.read_csv('input.csv') - data = rnp.numpify(point_cloud) - points = np.zeros([len(data['x']),3]) - points[...,0] = data['x'] - points[...,1] = data['y'] - points[...,2] = data['z'] - #data = rnp.numpify(point_cloud) - self.get_logger().info(str(points)) - #self.get_logger().info('#####################################################################################') - #pcd = o3d.geometry.PointCloud() - #pcd.points = o3d.utility.Vector3dVector(data) - #arr = np.asarray(pcd.points) - #print(arr.size) - occ = self.pcd_to_sensor_grid(data) - - width = 600 - height = 600 - fov = ShadowCaster(width, height) - for y in range(height): - for x in range(width): - if x == 0 or y == 0 or x == width - 1 or y == height - 1: - occ[x][y] = False - - result = fov.cast_shadow(occ, 299, 299, 240) - static_occ = np.zeros([height, width], dtype=int) - for y in range(height): - for x in range(width): - if result[x][y]: - if occ[x][y]: - static_occ[x][y] = 0 - else: - static_occ[x][y] = 1 - else: - static_occ[x][y] = 1 - ''' - StaticGrid grid - for row in static_occ: - GridRow tempRow - for value in row: - tempRow.append(value) - grid.append(tempRow) - ''' - #self.grid_pub.publish(grid) - msg = OccupancyGrid() - msg.header.stamp = Clock().clock - msg.header.frame_id = 'base_link' - msg.info.map_load_time = Clock().clock - msg.info.resolution = 0.4 - msg.info.width = width - msg.info.height = height - self.get_logger().info(str(static_occ.flatten())) - msg.data = [] - for i in static_occ.flatten(): - msg.data.append(i) - - self.grid_pub.publish(msg) - return static_occ - - def pcd_flattener(points: np.ndarray): - for point in points: - points[2] = 0 - return points - - def pcd_to_sensor_grid(self, points: np.ndarray): - rows = 600 - cols = 600 - #this grid creates the base for the egma we will send over to BPC - sensor_grid = [[True for i in range(cols)] for j in range(rows)] - for point in points: - x_cor = point[0] - y_cor = point[1] - x_cor = math.ceil(x_cor) - y_cor = math.ceil(y_cor) - sensor_grid[x_cor][y_cor] = False - - return sensor_grid - #return np.array(sensor_grid) - - - #def grid_to_image(arr: np.ndarray, path: str): - #cv2.imwrite(f'{path}.png',(arr * 255).astype(np.uint8)) - - - -def main(args=None): - rclpy.init(args=args) - dynamic_grid = DynamicGridNode() - rclpy.spin(dynamic_grid) - #self.get_logger().info('#####################################################################################') - dynamic_grid.destroy_node() - rclpy.shutdown() diff --git a/src/perception/dynamic_grid/dynamic_grid/grid_cell.py b/src/perception/dynamic_grid/dynamic_grid/grid_cell.py deleted file mode 100644 index e8bdb019b..000000000 --- a/src/perception/dynamic_grid/dynamic_grid/grid_cell.py +++ /dev/null @@ -1,32 +0,0 @@ -import numpy -import os -import math -import time - -import rclpy -from rclpy.node import Node -import ros2_numpy as rnp - -class GridCell(Node): - def __init__(self): - self.x = 0 - self.y = 0 - self.m_free = m_free - # posterior occupied mass - self.m_occ = m_occ - # normalization component for associated measurements - self.mu_A = 1. - # normalization component for unassociated measurements - self.mu_UA = 0. - # statistical moments: velocity - self.mean_x_vel = 0. - self.mean_y_vel = 0. - self.var_x_vel = 0. - self.var_y_vel = 0. - self.covar_xy_vel = 0. - # statistical moments: acceleration - self.mean_x_acc = 0. - self.mean_y_acc = 0. - self.var_x_acc = 0. - self.var_y_acc = 0. - self.covar_xy_acc = 0. diff --git a/src/perception/dynamic_grid/dynamic_grid/shadowcasting.py b/src/perception/dynamic_grid/dynamic_grid/shadowcasting.py deleted file mode 100644 index ca7be69e2..000000000 --- a/src/perception/dynamic_grid/dynamic_grid/shadowcasting.py +++ /dev/null @@ -1,236 +0,0 @@ -import math - - -class ShadowCaster: - - def __init__(self, mapwidth, mapheight): - self.width = mapwidth - self.height = mapheight - self.visiblemap = [] - self.seethrough = [] - self.sourcex = 0 - self.sourcey = 0 - self.range = 0 - - def cast_shadow(self, seethrough, sourcex, sourcey, sightrange): - self.sourcex = sourcex - self.sourcey = sourcey - self.range = sightrange - self.seethrough = seethrough - self.visiblemap = [[False for y in range(self.height)] - for x in range(self.width)] - self.visiblemap[sourcex][sourcey] = True - for octant in range(1, 9): - self._scan(1, octant, 1.0, 0.0) - return self.visiblemap - - def _scan(self, depth, octant, startslope, endslope): - x = 0 - y = 0 - if octant == 1: # NW - x = self.sourcex - int(startslope * depth) - y = self.sourcey - depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x - 1, y, False): - startslope = self._get_slope(x - .5, y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x - 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x - .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x += 1 - x -= 1 - elif octant == 2: # NE - x = self.sourcex + int(startslope * depth) - y = self.sourcey - depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x + 1, y, False): - startslope = -self._get_slope(x + .5, y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x + 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x + .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x -= 1 - x += 1 - elif octant == 3: # EN - x = self.sourcex + depth - y = self.sourcey - int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y - 1, False): - startslope = -self._get_inv_slope(x + .5, - y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y - 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x - .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y += 1 - y -= 1 - elif octant == 4: # ES - x = self.sourcex + depth - y = self.sourcey + int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y + 1, False): - startslope = self._get_inv_slope(x + .5, - y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y + 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x - .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y -= 1 - y += 1 - elif octant == 5: # SE - x = self.sourcex + int(startslope * depth) - y = self.sourcey + depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x + 1, y, False): - startslope = self._get_slope(x + .5, y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x + 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x + .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x -= 1 - x += 1 - elif octant == 6: # SW - x = self.sourcex - int(startslope * depth) - y = self.sourcey + depth - if self._check_bounds(x, y): - while self._get_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x - 1, y, False): - startslope = -self._get_slope(x - .5, y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x - 1, y, True): - self._scan(depth + 1, octant, startslope, - self._get_slope(x - .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - x += 1 - x -= 1 - elif octant == 7: # WS - x = self.sourcex - depth - y = self.sourcey + int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) <= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y + 1, False): - startslope = -self._get_inv_slope(x - .5, - y + .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y + 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x + .5, y + .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y -= 1 - y += 1 - elif octant == 8: # WN - x = self.sourcex - depth - y = self.sourcey - int(startslope * depth) - if self._check_bounds(x, y): - while self._get_inv_slope(x, y, self.sourcex, - self.sourcey) >= endslope: - if self._is_visible(x, y): - if self.seethrough[x][y]: - if self._test_tile(x, y - 1, False): - startslope = self._get_inv_slope(x - .5, - y - .5, - self.sourcex, - self.sourcey) - else: - if self._test_tile(x, y - 1, True): - self._scan(depth + 1, octant, startslope, - self._get_inv_slope(x + .5, y - .5, - self.sourcex, - self.sourcey)) - self.visiblemap[x][y] = True - y += 1 - y -= 1 - if x < 0: - x = 0 - if x >= self.width: - x = self.width - 1 - if y < 0: - y = 0 - if y >= self.height: - y = self.height - 1 - if self._is_visible(x, y) and self.seethrough[x][y]: - self._scan(depth + 1, octant, startslope, endslope) - - def _check_bounds(self, x, y): - if x < 0 or y < 0 or x >= self.width or y >= self.height: - return False - else: - return True - - def _get_slope(self, x1, y1, x2, y2): - return float(x1 - x2) / float(y1 - y2) - - def _get_inv_slope(self, x1, y1, x2, y2): - return float(y1 - y2) / float(x1 - x2) - - def _is_visible(self, x, y): - if self._check_bounds(self.sourcex, self.sourcey) and \ - self._check_bounds(x, y): - return math.hypot(self.sourcex - x, self.sourcey - y) <= self.range - else: - return False - - def _test_tile(self, x, y, state): - if not self._is_visible(x, y): - return False - else: - return self.seethrough[x][y] == state diff --git a/src/perception/dynamic_grid/setup.cfg b/src/perception/dynamic_grid/setup.cfg deleted file mode 100755 index b7a1cfc23..000000000 --- a/src/perception/dynamic_grid/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[develop] -script-dir=$base/lib/dynamic_grid -[install] -install-scripts=$base/lib/dynamic_grid diff --git a/src/perception/ground_seg/ground_seg.py b/src/perception/ground_seg/ground_seg.py deleted file mode 100644 index d768b53d5..000000000 --- a/src/perception/ground_seg/ground_seg.py +++ /dev/null @@ -1,170 +0,0 @@ -import numpy as np -import math -import itertools -import copy - -import rclpy -from rclpy.node import Node - -from sensor_msgs.msg import PointCloud2 -from std_msgs.msg import String - - -class GroundSeg(Node): - - def __init__(self): - super().__init__('ground_seg') - #===CONSTANTS===# - self.LiDAR_HEIGHT = -1.73 # initialize to the z-height of the LiDAR (in meters) - self.CAR_HEIGHT = 2 # initialize to the z-height of car (in meters) - self.RES = 1./3. - self.S = 0.09 - - #===PARAMETERS===# - self.lidar_sub = self.create_subscription(PointCloud2, 'input_points', self.ground_seg, 10) - self.ground_seg_pts_pub = self.create_publisher(PointCloud2, 'ground_seg_points', 10) - - #===================IGNOR============================================= - # self.publisher_ = self.create_publisher(String, 'topic', 10) - # timer_period = 0.5 # seconds - # self.timer = self.create_timer(timer_period, self.timer_callback) - # self.i = 0 - # - #def timer_callback(self): - # msg = String() - # msg.data = 'Hello World: %d' % self.i - # self.publisher_.publish(msg) - # self.get_logger().info('Publishing: "%s"' % msg.data) - # self.i += 1 - #===================================================================== - - def ground_seg(self, point_cloud: PointCloud2, res: float =None, s: float =None): - - # initializing parameters if none are given - if res == None: - res = self.RES - - if s == None: - s = self.S - - num_points = point_cloud.shape[0] - - # generate 2-D grid of the LiDAR cloud - max_index = math.sqrt(2.)*(128/3./2.+1.) - - # a 2D array that contains lists of 3D points in point_cloud that map to - # a particular grid cell (according to the place of the 3D point in point_cloud) - # a math.ceil is rounding numbers up, for example math.ceil(4.3) = 5 and math.ceil(-3.3) = -3 - filler = np.frompyfunc(lambda x: list(), 1, 1) - grid = np.empty((int(2 * math.ceil(max_index/res) + 1), int(2 * math.ceil(max_index/res) + 1)), dtype=np.object) - filler(grid, grid); - - # determine the center coordinate of the 2D grid - center_x = int(math.ceil(max_index/res)) - center_y = int(math.ceil(max_index/res)) - - for i in range(num_points): - point = point_cloud[i,:] - x = point[0] - y = point[1] - z = point[2] - - if ((math.fabs(x) <= max_index) and (math.fabs(y) <= max_index) and (z <= 3.5)): - - grid[int(center_x + round(x/res)), int(center_y + round(y/res))].append(i) - - h_G = np.nan*np.empty((grid.shape)) - - # iterate radially outwards to compute if a point belongs to the ground (1) on mask grid - grid_seg = np.zeros(grid.shape) - - # initialize the center coordinate of the 2D grid to ground - points_z = np.ndarray.tolist(point_cloud[grid[center_x, center_y],2]) - H = max(points_z or [np.nan]) - - if not math.isnan(H): - h_G[center_x, center_y] = H - else: - h_G[center_x, center_y] = self.LiDAR_HEIGHT - - # initialize the coordinates of inner circle - circle_inner = [[center_x, center_y]] - - # identify all the points that were labeled as not ground - point_cloud_seg = np.empty((0,3)) - - for i in range(1,int(math.ceil(max_index/res))+1): - - # generate indices at the ith inner circle level - circle_curr = generate_circle(i, center_x, center_y) - - for indices in circle_curr: - x = indices[0] - y = indices[1] - - # compute h_hat_G: find max h_G of neighbors - neigh_indeces = np.array(get_neighbors(x,y,circle_inner)) - - # compute the min and max z coordinates of each grid cell - points_z = np.ndarray.tolist(point_cloud[grid[x,y],2]) - H = max(points_z or [np.nan]) - h = min(points_z or [np.nan]) - - h_hat_G = np.nanmax(h_G[neigh_indeces]) - - if ((not np.isnan(H)) and (not np.isnan(h)) and \ - (H - h < s) and (H - h_hat_G < s)): - grid_seg[x,y] = 1 - h_G[x,y] = copy.deepcopy(H) - - else: - - h_G[x,y] = copy.deepcopy(h_hat_G) - - # add to not ground points - point_locations = grid[x,y] - - if point_locations != []: - point_cloud_seg = np.vstack((point_cloud_seg,point_cloud[point_locations,:])) - - # update the inner circle indices - circle_inner = copy.deepcopy(circle_curr) - - return point_cloud_seg - - # return the indices of a circle at level i from the center of the grid - def generate_circle(self, i: int, center_x: int, center_y: int): - - circle_range = range(-1*i,i+1) - circle = [list(x) for x in itertools.product(circle_range, circle_range)] - circle = [[item[0]+center_x, item[1]+center_y] for item in circle if ((abs(item[0]) == i) or (abs(item[1]) == i))] - - return circle - - # get the inner circle neighbors of a point - def get_neighbors(self, x, y, circle_inner: [[int, int]]): - neigh_indices = [] - for indices in circle_inner: - if ((abs(x-indices[0]) < 2) and (abs(y-indices[1]) < 2)): - neigh_indices.append(indices) - - return neigh_indices - - -def main(args=None): - rclpy.init(args=args) - - ground_seg = GroundSeg() - - rclpy.spin(ground_seg) - - # Destroy the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - ground_seg.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() - diff --git a/src/perception/ground_seg/ground_seg/ground_seg.py b/src/perception/ground_seg/ground_seg/ground_seg.py deleted file mode 100644 index 23dd8cd21..000000000 --- a/src/perception/ground_seg/ground_seg/ground_seg.py +++ /dev/null @@ -1,194 +0,0 @@ -import numpy as np -import ros2_numpy as rnp -import math -import itertools -import copy - -import rclpy -from rclpy.node import Node -from rosgraph_msgs.msg import Clock -from sensor_msgs.msg import PointCloud2 -from std_msgs.msg import String - - -class GroundSeg(Node): - - def __init__(self): - super().__init__('ground_seg') - - #===CONSTANTS===# - self.LiDAR_HEIGHT = -1.73 # initialize to the z-height of the LiDAR (in meters) - self.CAR_HEIGHT = 2 # initialize to the z-height of car (in meters) - self.RES = 1./3. - self.S = 0.09 - - #===PARAMETERS===# - self.lidar_sub = self.create_subscription(PointCloud2, '/lidar_filtered', self.simple_ground_seg, 10) - self.ground_seg_pts_pub = self.create_publisher(PointCloud2, '/lidar_finished', 10) - - def simple_ground_seg(self, msg: PointCloud2): - pcd = rnp.numpify(msg) - - #removes pcd data (z axis) below car height (2) - pcd = pcd[pcd['z'] >= -self.CAR_HEIGHT] - msg = rnp.msgify(PointCloud2, pcd) - - msg.header.frame_id = 'hero/lidar' - msg.header.stamp = Clock().clock - - #return point_cloud_seg - # self.get_logger().info('Publishing: simpl ground seg is DONE') - self.ground_seg_pts_pub.publish(msg) - - def ground_seg(self, msg: PointCloud2, res: float =None, s: float =None): - - # make an array of points from PointCloud2. - # ex: PointClouyd2 array --> [[x1,y1,z1], [x2,y2,z2],...] - point_cloud = rnp.numpify(msg) - - # initializing parameters if none are given - if res == None: - res = self.RES - - if s == None: - s = self.S - - num_points = point_cloud.shape[0] - - # generate 2-D grid of the LiDAR cloud - max_index = math.sqrt(2.)*(128/3./2.+1.) - - # a 2D array that contains lists of 3D points in point_cloud that map to - # a particular grid cell (according to the place of the 3D point in point_cloud) - # a math.ceil is rounding numbers up, for example math.ceil(4.3) = 5 and math.ceil(-3.3) = -3 - filler = np.frompyfunc(lambda x: list(), 1, 1) - grid = np.empty((int(2 * math.ceil(max_index/res) + 1), int(2 * math.ceil(max_index/res) + 1)), dtype=np.object) - filler(grid, grid); - - # determine the center coordinate of the 2D grid - center_x = int(math.ceil(max_index/res)) - center_y = int(math.ceil(max_index/res)) - - for i in range(num_points): - point = point_cloud[i,:] - #self.get_logger().info('Publishing: "%s"' % msg) - #self.get_logger().info('Publishing: "%s"' % point_cloud) - self.get_logger().info('Publishing: "%s"' % num_points) - self.get_logger().info('Publishing: "%s"' % point) - x = point[0] - y = point[1] - z = point[2] - - if ((math.fabs(x) <= max_index) and (math.fabs(y) <= max_index) and (z <= 3.5)): - - grid[int(center_x + round(x/res)), int(center_y + round(y/res))].append(i) - - h_G = np.nan*np.empty((grid.shape)) - - # iterate radially outwards to compute if a point belongs to the ground (1) on mask grid - grid_seg = np.zeros(grid.shape) - - # initialize the center coordinate of the 2D grid to ground - points_z = np.ndarray.tolist(point_cloud[grid[center_x, center_y],2]) - H = max(points_z or [np.nan]) - - if not math.isnan(H): - h_G[center_x, center_y] = H - else: - h_G[center_x, center_y] = self.LiDAR_HEIGHT - - # initialize the coordinates of inner circle - circle_inner = [[center_x, center_y]] - - # identify all the points that were labeled as not ground - point_cloud_seg = np.empty((0,3)) - - for i in range(1,int(math.ceil(max_index/res))+1): - - # generate indices at the ith inner circle level - circle_curr = self.generate_circle(i, center_x, center_y) - - for indices in circle_curr: - x = indices[0] - y = indices[1] - - # compute h_hat_G: find max h_G of neighbors - neigh_indeces = np.array(self.get_neighbors(x,y,circle_inner)) - - # compute the min and max z coordinates of each grid cell - points_z = np.ndarray.tolist(point_cloud[grid[x,y],2]) - H = max(points_z or [np.nan]) - h = min(points_z or [np.nan]) - - h_hat_G = np.nanmax(h_G[neigh_indeces]) - - if ((not np.isnan(H)) and (not np.isnan(h)) and \ - (H - h < s) and (H - h_hat_G < s)): - grid_seg[x,y] = 1 - h_G[x,y] = copy.deepcopy(H) - - else: - - h_G[x,y] = copy.deepcopy(h_hat_G) - - # add to not ground points - point_locations = grid[x,y] - - if point_locations != []: - point_cloud_seg = np.vstack((point_cloud_seg,point_cloud[point_locations,:])) - - # update the inner circle indices - circle_inner = copy.deepcopy(circle_curr) - - #return point_cloud_seg - self.ground_seg_pts_pub.publish(self.array_to_msg(point_cloud_seg)) - - # return the indices of a circle at level i from the center of the grid - def generate_circle(self, i, center_x, center_y): - - circle_range = range(-1*i,i+1) - circle = [list(x) for x in itertools.product(circle_range, circle_range)] - circle = [[item[0]+center_x, item[1]+center_y] for item in circle if ((abs(item[0]) == i) or (abs(item[1]) == i))] - - return circle - - # get the inner circle neighbors of a point - def get_neighbors(self, x, y, circle_inner): - neigh_indices = [] - for indices in circle_inner: - if ((abs(x-indices[0]) < 2) and (abs(y-indices[1]) < 2)): - neigh_indices.append(indices) - - return neigh_indices - - def array_to_msg(nparray: np.array): - data = np.zeros(len(nparray), dtype=[ - ('x', np.float32), - ('y', np.float32), - ('z', np.float32) - ]) - data['x'] = nparray[:,0] - data['y'] = nparray[:,1] - data['z'] = nparray[:,2] - - msg = ros2_numpy.msgify(PointCloud2, data, stamp=header.stamp, frame_id=header.frame_id) - - return msg - -def main(args=None): - rclpy.init(args=args) - - ground_seg = GroundSeg() - - rclpy.spin(ground_seg) - - # Destroy the node explicitly - # (optional - otherwise it will be done automatically - # when the garbage collector destroys the node object) - ground_seg.destroy_node() - rclpy.shutdown() - - -if __name__ == '__main__': - main() - diff --git a/src/perception/ground_seg/package.xml b/src/perception/ground_seg/package.xml deleted file mode 100644 index 2944f649b..000000000 --- a/src/perception/ground_seg/package.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - ground_seg - 1.0.0 - Deletes all the ground points - santonyuk - MIT - - python3-pytest - - - ament_python - - diff --git a/src/perception/ground_seg/setup.cfg b/src/perception/ground_seg/setup.cfg deleted file mode 100644 index 61aacf83f..000000000 --- a/src/perception/ground_seg/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[develop] -script-dir=$base/lib/ground_seg -[install] -install-scripts=$base/lib/ground_seg diff --git a/src/perception/ground_seg/setup.py b/src/perception/ground_seg/setup.py deleted file mode 100644 index 24385c936..000000000 --- a/src/perception/ground_seg/setup.py +++ /dev/null @@ -1,23 +0,0 @@ -from setuptools import setup - -package_name = 'ground_seg' - -setup( - name=package_name, - version='1.0.0', - packages=[package_name], - data_files=[ - ('share/ament_index/resource_index/packages', ['resource/' + package_name]), - ('share/' + package_name, ['package.xml']), - ], - install_requires=['setuptools'], - zip_safe=True, - maintainer='santonyuk', - maintainer_email='stepan.antonyuk@gmil.com', - description='Deletes all the ground points', - license='MIT', - tests_require=['pytest'], - entry_points={ - 'console_scripts': ['ground_seg = ground_seg.ground_seg:main'], - }, -) diff --git a/src/perception/mapping/README.md b/src/perception/mapping/README.md deleted file mode 100755 index 7c14078d0..000000000 --- a/src/perception/mapping/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# can_interface - -Provides a ROS node that allows CAN messages to be sent and received -as messages on ROS topics. The custom library used internally to -interact with the CAN bus is also available. - -## Node Features - -- Simple interface - CAN frames are represented by simple ROS messages - that only include two values - one for the identifier and one for - the data. Simply subscribe to or publish on the provided topics to - interface with the CAN bus. - -- No echo - Messages being sent are published on a different topic - than messages being received. This means that messages we send will - not be "echoed" back to us by the CAN interface. - -- Multiple interfaces - This node obviously needs to be provided with - an interface name (e.g., "can0"). It then names the used topics - based on that interface ("outgoing_can_messages_" - and "incoming_can_messages_"). This means that we - can start multiple copies of this node on different interfaces - without them interfering with one another. - -- Error handling - This node includes procedures to deal with errors - that arise during operation. These may include re-initializing the - CAN bus, contacting a safety node, waiting and retrying, etc. (not - yet implemented!) - -## API Features - -- Object-oriented interface - CAN buses are instantiated as objects - and therefore come with all of the nice features of C++ objects. The - bus is automatically closed on object destruction. - -- Simplicity - Connecting to a bus is as easy as `new - CanBus("can0");`. Supports checking whether there is a frame ready - for reading (to facilitate non-blocking I/O) through a simple - instance method. Reading and writing frames are as simple as a - function call each. - -- Exceptions - Rather than setting arcane error bits and returning -1, - this library will throw actual, useful exceptions when things go - wrong. This leaves your code free to handle errors as you please - without extra overhead. (not yet implemented!) - -## Notes - -- When testing this package (using `colcon test`), you must have a - virtual CAN bus named "vcan0" available on your system. Otherwise, - the provided tests will fail. It's also worth noting that the tests - may fail if the bus is noisy when the tests are run. diff --git a/src/perception/mapping/exe/octree_mapper.cpp b/src/perception/mapping/exe/octree_mapper.cpp deleted file mode 100755 index 6371752a5..000000000 --- a/src/perception/mapping/exe/octree_mapper.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Package: mapping - * Filename: octree_mapper.cpp - * Author: Will Heitman - * Email: w at heit dot mn - * Copyright: 2023, Nova UTD - * License: MIT License - */ - -#include -#include // std::make_shared -#include "rclcpp/rclcpp.hpp" -#include "mapping/OctoSlamNode.hpp" - -int main(int argc, char **argv) -{ - rclcpp::init(argc, argv); - - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} diff --git a/src/perception/mapping/include/mapping/OctoSlamNode.hpp b/src/perception/mapping/include/mapping/OctoSlamNode.hpp deleted file mode 100755 index 5c082c1ba..000000000 --- a/src/perception/mapping/include/mapping/OctoSlamNode.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Package: mapping - * Filename: OctoSlamNode.hpp - * Author: Will Heitman - * Email: w at heit dot mn - * Copyright: 2023, Nova UTD - * License: MIT License - */ - -#pragma once - -#include "mapping/ParticleFilter.hpp" - -// Message definitions -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "rclcpp/rclcpp.hpp" -#include "pcl_conversions/pcl_conversions.h" -#include "pcl_ros/transforms.hpp" -#include -#include -#include - -#include -#include -#include "tf2_ros/transform_broadcaster.h" -#include -#include - -using namespace std::chrono_literals; - -namespace navigator -{ - namespace perception - { - - class OctoSlamNode : public rclcpp::Node - { - public: - OctoSlamNode(); - virtual ~OctoSlamNode(); - - private: - // Constants - // TODO: Convert to ROS parameters - const double OCTREE_RESOLUTION = 0.2; // meters - const int MAX_VISUALIZATION_DEPTH = 16; // A depth of 16 = 0.2 meters, 15 = 0.4 meters, 14 = 0.8... - std::chrono::milliseconds MAP_UPDATE_PERIOD = 200ms; - const std::string MAP_SAVE_PATH = "/navigator/data/maps/"; - const double HIGH_RES_DISTANCE = 20; // meters - const double MED_RES_DISTANCE = 40; // meters - const std::string INITIAL_GUESS_ODOM_TOPIC = "/odometry/gnss_processed"; - - // Publishers - rclcpp::Publisher::SharedPtr voxel_marker_pub; - rclcpp::Publisher::SharedPtr particle_viz_pub; - std::unique_ptr tf_broadcaster; - - // Subscribers - rclcpp::Subscription::SharedPtr world_info_sub; - rclcpp::Subscription::SharedPtr initial_odom_sub; - rclcpp::Subscription::SharedPtr clock_sub; - rclcpp::Subscription::SharedPtr pcd_sub; - - // Callbacks - void gnssOdomCb(nav_msgs::msg::Odometry::SharedPtr msg); - void pointCloudCb(sensor_msgs::msg::PointCloud2::SharedPtr msg); - void worldInfoCb(carla_msgs::msg::CarlaWorldInfo::SharedPtr msg); - - // Timers - rclcpp::TimerBase::SharedPtr map_marker_timer; - - rosgraph_msgs::msg::Clock clock; - std::string map_name; - geometry_msgs::msg::TransformStamped map_bl_transform; - pcl::PointCloud latest_cloud; // TODO: Make this shared_ptr? - std::shared_ptr filter; - std::shared_ptr tree; - - std::string getFilenameFromMapName(); - octomap::Pointcloud pclToOctreeCloud(pcl::PointCloud inputCloud); - void publishMapMarker(); - void saveOctreeBinary(); - - std::unique_ptr tf_buffer_ = std::make_unique(this->get_clock()); - std::shared_ptr tf_listener_ = std::make_shared(*tf_buffer_); - }; - - } -} diff --git a/src/perception/mapping/include/mapping/ParticleFilter.hpp b/src/perception/mapping/include/mapping/ParticleFilter.hpp deleted file mode 100755 index ff0958f49..000000000 --- a/src/perception/mapping/include/mapping/ParticleFilter.hpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Package: mapping - * Filename: ParticleFilter.hpp - * Author: Will Heitman - * Email: w at heit dot mn - * Copyright: 2023, Nova UTD - * License: MIT License - */ - -#pragma once - -// Message definitions -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include // partial sum (cumulative sum) -#include // normal distributions -#include - -#include "rclcpp/rclcpp.hpp" -#include "pcl_conversions/pcl_conversions.h" -#include "pcl_ros/transforms.hpp" -#include -#include -#include - -#include -#include -#include -#include - -using namespace std::chrono_literals; - -using geometry_msgs::msg::PoseWithCovarianceStamped; -using sensor_msgs::msg::Imu; -using sensor_msgs::msg::PointCloud2; -namespace navigator -{ - namespace perception - { - - struct Pose - { - double x; - double y; - double h; // heading, in radians - - Pose(double x = 0.0, double y = 0.0, double h = 0.0) : x(x), y(y), h(h) - { - } - - Pose operator+(const Pose &a) const - { - Pose result(a.x + x, a.y + y, a.h + h); - result.h = fmod(result.h, M_2_PI); - return result; - } - Pose operator-(const Pose &a) const - { - Pose result(a.x - x, a.y - y, a.h - h); - result.h = fmod(result.h, M_2_PI); - return result; - } - }; - struct Particle : Pose - { - double w; // weight, the probability of a particle from [0.,1.] - Particle(double x = 0.0, double y = 0.0, double h = 0.0, double w = 0.0) : Pose(x, y, h), w(w) - { - } - }; - - class ParticleFilter - { - public: - ParticleFilter(int num_particles, const octomap::OcTree &tree) : tree(tree), num_particles(num_particles), is_initialized(false) {} - virtual ~ParticleFilter(); - - void init(double x, double y, double h, double std[]); - - void addMeasurement(Imu imu_msg); - void predictMotion(Pose new_gnss_pose); - void updateWeights(); - void resample(); - - const bool isReady() const; - - PoseWithCovarianceStamped generatePose(); - - PointCloud2 asPointCloud(); - PoseWithCovarianceStamped update(pcl::PointCloud observation, Pose gnss_pose); - - private: - int num_particles; - bool is_initialized; - std::vector weights; - std::vector particles; - Pose gnss_pose_cached; - pcl::PointCloud latest_observation; - const octomap::OcTree &tree; - - double getParticleScore(const Particle p, pcl::PointCloud observation); - }; - - } -} diff --git a/src/perception/mapping/package.xml b/src/perception/mapping/package.xml deleted file mode 100755 index ef5335200..000000000 --- a/src/perception/mapping/package.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - mapping - 1.0.0 - Map creation, provision, and storage tools. - Will Heitman - MIT License - - nova_auto_package - - carla_msgs - geometry_msgs - nav_msgs - octomap - pcl - pcl_ros - rclcpp - rosgraph_msgs - sensor_msgs - tf2_eigen - tf2_ros - visualization_msgs - - - ament_cmake - - \ No newline at end of file diff --git a/src/perception/mapping/src/OctoSlamNode.cpp b/src/perception/mapping/src/OctoSlamNode.cpp deleted file mode 100755 index c8c9266b5..000000000 --- a/src/perception/mapping/src/OctoSlamNode.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Package: mapping - * Filename: OctoSlamNode.cpp - * Author: Will Heitman - * Email: w at heit dot mn - * Copyright: 2023, Nova UTD - * License: MIT License - */ - -#include "mapping/OctoSlamNode.hpp" - -using namespace navigator::perception; -using namespace std::chrono_literals; - -using carla_msgs::msg::CarlaWorldInfo; -using geometry_msgs::msg::Point; -using geometry_msgs::msg::TransformStamped; -using geometry_msgs::msg::Vector3; -using nav_msgs::msg::Odometry; -using rosgraph_msgs::msg::Clock; -using sensor_msgs::msg::PointCloud2; -using std_msgs::msg::ColorRGBA; -using visualization_msgs::msg::Marker; - -struct Particle -{ - double x; - double y; - double theta; - double weight; -}; - -OctoSlamNode::OctoSlamNode() : Node("octree_mapping_node") -{ - // Subscribe to and use CARLA's clock - clock_sub = this->create_subscription( - "/clock", 10, - [this](Clock::SharedPtr msg) - { this->clock = *msg; }); - - pcd_sub = this->create_subscription( - "/lidar_filtered", 10, - std::bind(&OctoSlamNode::pointCloudCb, this, std::placeholders::_1)); - - initial_odom_sub = this->create_subscription( - INITIAL_GUESS_ODOM_TOPIC, 10, - std::bind(&OctoSlamNode::gnssOdomCb, this, std::placeholders::_1)); - - world_info_sub = this->create_subscription( - "/carla/world_info", 10, - std::bind(&OctoSlamNode::worldInfoCb, this, std::placeholders::_1)); - - voxel_marker_pub = this->create_publisher("/map/voxels/viz", 10); - particle_viz_pub = this->create_publisher("/map/particles/viz", 10); - - this->map_marker_timer = this->create_wall_timer(this->MAP_UPDATE_PERIOD, - bind(&OctoSlamNode::publishMapMarker, this)); - - this->tf_broadcaster = std::make_unique(*this); -} - -void OctoSlamNode::gnssOdomCb(Odometry::SharedPtr msg) -{ - // Initialize our filter given the initial guess - if (this->filter == nullptr) - { - if (this->tree == nullptr) - return; - this->filter = std::make_shared(100, *this->tree); - - auto q_msg = msg->pose.pose.orientation; - Eigen::Quaternionf q(q_msg.w, q_msg.x, q_msg.y, q_msg.z); - auto heading = q.toRotationMatrix().eulerAngles(0, 1, 2)[2]; - - double stdev[3] = {3.0, 3.0, 0.3}; - - this->filter->init( - msg->pose.pose.position.x, - msg->pose.pose.position.y, - heading, - stdev); - RCLCPP_INFO(this->get_logger(), "Particle filter has been created."); - } - - // Extract yaw from msg quaternion - auto q_msg = msg->pose.pose.orientation; - Eigen::Quaternionf q(q_msg.w, q_msg.x, q_msg.y, q_msg.z); - double yaw = q.toRotationMatrix().eulerAngles(0, 1, 2)[2]; - - navigator::perception::Pose gnss_pose( - msg->pose.pose.position.x, - msg->pose.pose.position.y, - yaw); - - // filter->update() runs one iteration of the particle filter, - // handling all internal steps, then returns the result pose. - PoseWithCovarianceStamped filter_result = this->filter->update(this->latest_cloud, gnss_pose); - RCLCPP_INFO(this->get_logger(), "097"); - - map_bl_transform = TransformStamped(); - - map_bl_transform.header.stamp = this->clock.clock; - map_bl_transform.header.frame_id = "map"; - map_bl_transform.child_frame_id = "hero"; - map_bl_transform.transform.translation.x = filter_result.pose.pose.position.x; - map_bl_transform.transform.translation.y = filter_result.pose.pose.position.y; - map_bl_transform.transform.translation.z = filter_result.pose.pose.position.z; // This should be zero. - map_bl_transform.transform.rotation = filter_result.pose.pose.orientation; - this->tf_broadcaster->sendTransform(map_bl_transform); - - PointCloud2 particle_cloud = this->filter->asPointCloud(); - particle_viz_pub->publish(particle_cloud); -} - -void OctoSlamNode::publishMapMarker() -{ - // If the tree is uninitialized, skip - if (this->tree == nullptr) - return; - - pcl::PointCloud pcl_cloud; - - // Convert from ROS to PCL format - - // Location of vehicle as a ROS vector - Vector3 center_ros = map_bl_transform.transform.translation; - - // Set the bounds of our bounding box - octomap::point3d hi_res_bbx_min_pt( - center_ros.x - HIGH_RES_DISTANCE, - center_ros.y - HIGH_RES_DISTANCE, - center_ros.z - HIGH_RES_DISTANCE); - octomap::point3d hi_res_bbx_max_pt( - center_ros.x + HIGH_RES_DISTANCE, - center_ros.y + HIGH_RES_DISTANCE, - center_ros.z + HIGH_RES_DISTANCE); - - // Iterate through each point in the tree - for ( - octomap::OcTree::leaf_bbx_iterator it = tree->begin_leafs_bbx(hi_res_bbx_min_pt, hi_res_bbx_max_pt, MAX_VISUALIZATION_DEPTH), - end = tree->end_leafs_bbx(); - it != end; ++it) - { - - if (it->getOccupancy() < 0.8) - continue; // Skip unoccupied cells - // RCLCPP_INFO(this->get_logger(), "Occ: %f, val: %f", it->getOccupancy(), it->getValue()); - // manipulate node, e.g.:44 - octomap::point3d voxel_center = it.getCoordinate(); - pcl::PointXYZI voxel_center_pcl; - voxel_center_pcl.x = voxel_center.x(); - voxel_center_pcl.y = voxel_center.y(); - voxel_center_pcl.z = voxel_center.z(); - - pcl_cloud.push_back(voxel_center_pcl); - } - - PointCloud2 ros_cloud; - - pcl::toROSMsg(pcl_cloud, ros_cloud); - ros_cloud.header.frame_id = "map"; - ros_cloud.header.stamp = this->clock.clock; - - voxel_marker_pub->publish(ros_cloud); -} - -void OctoSlamNode::pointCloudCb(PointCloud2::SharedPtr ros_cloud) -{ - auto now = this->get_clock()->now(); - double start_seconds = now.seconds() + now.nanoseconds() * 1e-9; - - if (this->tree == nullptr) - return; // Tree not yet initialized - - octomap::Pointcloud octo_cloud; - pcl::PointCloud pcl_cloud; - - // Convert from ROS to PCL format - pcl::fromROSMsg(*ros_cloud, pcl_cloud); - - // Convert the TransformStamped message that we just received - // into an Eigen-style transform - Eigen::Matrix4f baselink_to_map_tf = tf2::transformToEigen(map_bl_transform.transform).matrix().cast(); - - // Use the Eigen transform to transform the pcl cloud to the global "map" frame - pcl::transformPointCloud(pcl_cloud, pcl_cloud, baselink_to_map_tf); - - Vector3 tf_translation = map_bl_transform.transform.translation; - octomap::point3d sensor_origin( - tf_translation.x, tf_translation.y, tf_translation.z); - - tree->insertPointCloud(pclToOctreeCloud(pcl_cloud), sensor_origin); - this->latest_cloud = pcl_cloud; // Cache the latest LiDAR data for the particle filter - now = this->get_clock()->now(); - double end_seconds = now.seconds() + now.nanoseconds() * 1e-9; - - double delta_t = end_seconds - start_seconds; - RCLCPP_INFO(this->get_logger(), "Took %f seconds", delta_t); -} - -/** - * @brief Given a PCL-formatted cloud, return an Octomap-formatted version - * - * @param inputCloud The PCL-formatted cloud - * @return octomap::Pointcloud - */ -octomap::Pointcloud OctoSlamNode::pclToOctreeCloud(pcl::PointCloud inputCloud) -{ - octomap::Pointcloud result; - for (pcl::PointXYZI pt : inputCloud) - { - result.push_back(pt.x, pt.y, pt.z); - } - RCLCPP_DEBUG(this->get_logger(), "Adding %d points", inputCloud.size()); - return result; -} - -/** - * @brief Generate the map's filename, including the path - * - * @return std::string - */ -std::string OctoSlamNode::getFilenameFromMapName() -{ - std::string file_name = this->map_name; - file_name.erase( - remove(file_name.begin(), file_name.end(), '/'), - file_name.end()); // remove '/' from string - - std::size_t ind = file_name.find("CarlaMaps"); // Remove "CarlaMaps" from name - if (ind != std::string::npos) - { - file_name.erase(ind, std::string("CarlaMaps").length()); - std::cout << file_name << "\n"; - } - - std::transform(file_name.begin(), file_name.end(), - file_name.begin(), ::tolower); // Convert to lowercase - - file_name = MAP_SAVE_PATH + file_name + ".bt"; - return file_name; -} - -/** - * @brief Save the octree to disk in the Octomap format. - * - */ -void OctoSlamNode::saveOctreeBinary() -{ - std::string file_name = getFilenameFromMapName(); - RCLCPP_INFO(this->get_logger(), "Saving map to " + file_name); - - tree->writeBinary(file_name); -} - -/** - * @brief Either load or create a map from a given map name - * - * @param msg The world info message containing the map name - */ -void OctoSlamNode::worldInfoCb(CarlaWorldInfo::SharedPtr msg) -{ - if (this->tree != nullptr) - return; // Tree already initialized - - this->map_name = msg->map_name; - std::string file_name = getFilenameFromMapName(); - - // if (file_name == ".bt") - // { - // RCLCPP_WARN(this->get_logger(), "Map name is empty, waiting until map is loaded." + file_name); - // } - - RCLCPP_INFO(this->get_logger(), "Reading map from " + file_name); - - this->tree = std::make_shared(OCTREE_RESOLUTION); - - bool successfully_read = this->tree->readBinary(file_name); - - if (!successfully_read) - { - this->tree = std::make_shared(this->OCTREE_RESOLUTION); - RCLCPP_INFO(this->get_logger(), "Map file did not exist. A new one will be created."); - } - else - { - RCLCPP_INFO(this->get_logger(), "Reading complete."); - } -} - -/** - * @brief Destroy the Octree node, saving the map to disk first. - * - */ -OctoSlamNode::~OctoSlamNode() -{ - saveOctreeBinary(); -} diff --git a/src/perception/mapping/src/ParticleFilter.cpp b/src/perception/mapping/src/ParticleFilter.cpp deleted file mode 100755 index 43252099c..000000000 --- a/src/perception/mapping/src/ParticleFilter.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Package: mapping - * Filename: ParticleFilter.cpp - * Author: Will Heitman - * Email: w at heit dot mn - * Copyright: 2023, Nova UTD - * License: MIT License - * - * General steps to particle filters: - * 1. Generate a random set of particles in a normal distribution around an initial guess - * 2. Given odometry, predict the motion of all particles and update their poses - * 3. Given observations, assign a weight (probability) to each particle - * 4. Resample the particles, removing or copying each, based on their weights - * 5. Calculate the pose using the mean and stddev of the particles - * 6. Repeat 2-5 in a loop. - */ - -#include "mapping/ParticleFilter.hpp" - -#include - -using namespace navigator::perception; -using namespace std::chrono_literals; -typedef pcl::PointCloud PclCloud; - -const bool ParticleFilter::isReady() const -{ - return is_initialized; -} - -PoseWithCovarianceStamped ParticleFilter::update(PclCloud observation, Pose gnss_pose) -{ - std::printf("Updating...\n"); - - // TODO: Make this more efficient. This copy is likely expensive. - this->latest_observation = observation; - - auto start = std::chrono::high_resolution_clock::now(); - this->predictMotion(gnss_pose); - auto stop = std::chrono::high_resolution_clock::now(); - int duration = std::chrono::duration_cast(stop - start).count(); - std::printf("Motion update complete in %i ms\n", duration); - - start = std::chrono::high_resolution_clock::now(); - this->updateWeights(); - stop = std::chrono::high_resolution_clock::now(); - duration = std::chrono::duration_cast(stop - start).count(); - std::printf("Weight update complete in %i ms\n", duration); - - start = std::chrono::high_resolution_clock::now(); - this->resample(); - stop = std::chrono::high_resolution_clock::now(); - duration = std::chrono::duration_cast(stop - start).count(); - std::printf("Resample complete in %i ms\n", duration); - - gnss_pose_cached = gnss_pose; - - start = std::chrono::high_resolution_clock::now(); - PoseWithCovarianceStamped result = generatePose(); - stop = std::chrono::high_resolution_clock::now(); - duration = std::chrono::duration_cast(stop - start).count(); - std::printf("Weight update complete in %i ms\n", duration); - - printf("Result: (%f,%f,%f)/(%f,%f,%f,%f), N=%u\n", - result.pose.pose.position.x, - result.pose.pose.position.y, - result.pose.pose.position.z, - result.pose.pose.orientation.w, - result.pose.pose.orientation.x, - result.pose.pose.orientation.y, - result.pose.pose.orientation.z, - this->particles.size()); - return result; -} - -/** - * @brief Add predicted displacement, plus noise, to each particle - * - * @param new_gnss_pose The latest (x,y,h) from the GNSS. - */ -void ParticleFilter::predictMotion(Pose new_gnss_pose) -{ - Pose displacement = new_gnss_pose - gnss_pose_cached; - - // std::printf("Displacement: (%f,%f,%f)\n", - // displacement.x, - // displacement.y, - // displacement.h); - - std::normal_distribution<> dist_x{displacement.x, 4.0}; // 4m error -- actual GNSS error is ~2m - std::normal_distribution<> dist_y{displacement.y, 4.0}; - std::normal_distribution<> dist_h{displacement.h, 0.35}; // ~20 degrees error - - // Add predicted displacement, plus noise, to each particle - // std::printf("Was: (%f,%f,%f)\n", - // this->particles.front().x, - // this->particles.front().y, - // this->particles.front().h); - - std::default_random_engine rand_gen; - - auto p = this->particles.begin(); - while (p != this->particles.end()) - { - p->x += (displacement.x + dist_x(rand_gen)); - p->y += (displacement.y + dist_y(rand_gen)); - p->h += (displacement.h + dist_h(rand_gen)); - p->h = fmod(displacement.h, M_2_PI); // Wrap to [0, 2*pi] - p++; - } - - // std::printf("Is now: (%f,%f,%f)\n", - // this->particles.front().x, - // this->particles.front().y, - // this->particles.front().h); - - gnss_pose_cached = new_gnss_pose; -} - -double ParticleFilter::getParticleScore(const Particle p, PclCloud observation) -{ - double particle_score = 0.0; - - // 1. Transform observation from sensor frame to map frame - - Eigen::Matrix4f baselink_to_map_tf = Eigen::Matrix4f::Zero(); - /** - * https://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - * - * cos(h) -sin(h) 0 x - * sin(h) cos(h) 0 y - * 0 0 1 z - * 0 0 0 1 - */ - baselink_to_map_tf(0, 0) = cos(p.h); - baselink_to_map_tf(0, 1) = -1 * sin(p.h); - baselink_to_map_tf(1, 0) = sin(p.h); - baselink_to_map_tf(1, 1) = cos(p.h); - baselink_to_map_tf(2, 2) = 1.0; - baselink_to_map_tf(0, 3) = p.x; - baselink_to_map_tf(1, 3) = p.y; - baselink_to_map_tf(3, 3) = 1.0; - - // Use the Eigen transform to transform the pcl cloud to the global "map" frame - pcl::transformPointCloud(observation, observation, baselink_to_map_tf); - - for (pcl::PointXYZI pt : observation) - { - octomap::OcTreeNode *node = this->tree.search(pt.x, pt.y, pt.z, 15); // Depth of 15 = 0.4m - if (node == nullptr) - continue; // No points awarded if node not yet added to octree - particle_score += node->getOccupancy(); // [0.0, 1.0] - } - return particle_score; -} - -/** - * @brief Perform Sequential Importance Sampling - * - */ -void ParticleFilter::updateWeights() -{ - double total_score = 0.0; // Used to normalize the probability - - // Loop through each particle - auto p = this->particles.begin(); - while (p != this->particles.end()) - { - double score = getParticleScore(*p, latest_observation); - p->w *= score; // Bayes theorem: P(x|z) = (likelihood * prior) / normalization - total_score += score; - p++; - } - - // Normalize such that the sum of all weights = 1.0 - for (int i = 0; i < particles.size(); i++) - { - particles.at(i).w /= total_score; - weights.at(i) = particles.at(i).w; - } -} - -void ParticleFilter::resample() -{ - std::default_random_engine rand_eng; - - // A distribution from (0, weights.size()) where the probability - // of each element being chosen is based on each weight, such that - // higher weights are more likely to be selected. - std::discrete_distribution weighted_dist(weights.begin(), weights.end()); - - std::vector resampled_particles; - - const double GNSS_DISTANCE_THRESHOLD = 3.0; // Particles further than this distance will be removed. - - for (int i = 0; i < num_particles; i++) - { - Particle random_particle = particles[weighted_dist(rand_eng)]; - - double distance_from_gnss = sqrt( - pow(gnss_pose_cached.x - random_particle.x, 2) + - pow(gnss_pose_cached.y - random_particle.y, 2)); - - if (distance_from_gnss > GNSS_DISTANCE_THRESHOLD) - { - resampled_particles.push_back(Particle( - gnss_pose_cached.x, - gnss_pose_cached.y, - gnss_pose_cached.h, - random_particle.w)); - } - else - { - resampled_particles.push_back(random_particle); - } - } - - particles = resampled_particles; -} - -/** - * @brief - * - * @param x Initial x position from GNSS (m) - * @param y Initial y position from GNSS (m) - * @param heading Initial heading from GNSS (m) - * @param std [stdev_x, stdev_y, stdev_heading] (m) - */ -void ParticleFilter::init(double x, double y, double heading, double std[]) -{ - weights.resize(num_particles); - particles.resize(num_particles); - - gnss_pose_cached = Pose(x, y, heading); - - // Standard deviations for x, y, and theta - double std_x, std_y, std_heading; - std_x = std[0]; - std_y = std[1]; - std_heading = std[2]; - - // Normal distributions - std::normal_distribution dist_x(x, std_x); - std::normal_distribution dist_y(y, std_y); - std::normal_distribution dist_theta(heading, std_heading); - - std::default_random_engine rand_gen; - - // create particles and set their values - for (int i = 0; i < num_particles; ++i) - { - Particle p; - p.x = dist_x(rand_gen); // take a random value from the Gaussian Normal distribution and update the attribute - p.y = dist_y(rand_gen); - p.h = dist_theta(rand_gen); - p.w = 1; - - particles[i] = p; - weights[i] = p.w; - } - is_initialized = true; -} - -PoseWithCovarianceStamped ParticleFilter::generatePose() -{ - Pose mean_pose; - Pose variance_pose; - - // 1. Calculate mean - for (Particle p : this->particles) - { - mean_pose.x += p.x; - mean_pose.y += p.y; - mean_pose.h += p.h; - } - - mean_pose.x /= this->particles.size(); - mean_pose.y /= this->particles.size(); - mean_pose.h /= this->particles.size(); - mean_pose.h = fmod(mean_pose.h, M_2_PI); // Wrap to [0, 2*pi] - - // 2. Calculate variance - // https://en.wikipedia.org/wiki/Variance#Discrete_random_variable - for (Particle p : this->particles) - { - variance_pose.x += pow(p.x - mean_pose.x, 2); - variance_pose.y += pow(p.y - mean_pose.y, 2); - variance_pose.h += pow(p.h - mean_pose.h, 2); - } - variance_pose.x /= this->particles.size(); - variance_pose.y /= this->particles.size(); - variance_pose.h /= this->particles.size(); - variance_pose.h = fmod(variance_pose.h, M_2_PI); // Wrap to [0, 2*pi] - - // Construct quaternion from roll=0, pitch=0, yaw - Eigen::Quaternionf q; - q = Eigen::AngleAxisf(0.0, Eigen::Vector3f::UnitX()) * - Eigen::AngleAxisf(0.0, Eigen::Vector3f::UnitY()) * - Eigen::AngleAxisf(mean_pose.h, Eigen::Vector3f::UnitZ()); - - auto pose_msg = PoseWithCovarianceStamped(); - pose_msg.pose.pose.position.x = mean_pose.x; - pose_msg.pose.pose.position.y = mean_pose.y; - pose_msg.pose.pose.orientation.w = q.w(); - pose_msg.pose.pose.orientation.x = q.x(); - pose_msg.pose.pose.orientation.y = q.y(); - pose_msg.pose.pose.orientation.z = q.z(); - - // std::printf("Pose is now: (%f,%f,%f)\n", - // mean_pose.x, - // mean_pose.y, - // mean_pose.h); - - return pose_msg; -} - -PointCloud2 ParticleFilter::asPointCloud() -{ - pcl::PointCloud pcl_cloud; - for (Particle p : this->particles) - { - pcl::PointXYZRGB pt; - pt.x = p.x; - pt.y = p.y; - pt.z = 0.0; - pt.r = 100; - pt.g = 255; - pt.b = 0; - - pcl_cloud.push_back(pt); - } - - PointCloud2 ros_cloud; - pcl::toROSMsg(pcl_cloud, ros_cloud); - - ros_cloud.header.frame_id = "map"; - - return ros_cloud; -} - -ParticleFilter::~ParticleFilter() -{ -} diff --git a/src/perception/mapping/test/test_octree.cpp b/src/perception/mapping/test/test_octree.cpp deleted file mode 100755 index 47d7eb1ff..000000000 --- a/src/perception/mapping/test/test_octree.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Package: mapping - * Filename: test_can_bus.cpp - * Author: Joshua Williams - * Email: joshmackwilliams@protonmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -// // Test the CanBus class (isolated from the ROS node). Note that for -// // these tests to pass, you need to have a CAN bus named vcan0 -// // operational on your system. - -// #include // Testing framework -// #include // std::unique_ptr - -// #include "can_interface/CanBus.hpp" // The class we are testing, obviously -// #include "can_interface/CanFrame.hpp" // Needed to interact with CanBus - -// using namespace navigator::can_interface; - -// TEST(TestCanBus, test_intiializes) { -// CanBus my_bus("vcan0"); // If this passes, the test succeeds -// } - -// // Just testing for the general ability of these busses to communicate -// // with each other -// TEST(TestCanBus, test_communication) { -// CanBus bus1("vcan0"); -// CanBus bus2("vcan0"); -// ASSERT_FALSE(bus1.is_frame_ready()); -// ASSERT_FALSE(bus2.is_frame_ready()); -// CanFrame my_frame(0x292, 0x1234567890123456u); -// bus1.write_frame(my_frame); -// ASSERT_FALSE(bus1.is_frame_ready()); -// ASSERT_TRUE(bus2.is_frame_ready()); -// std::unique_ptr received_frame = bus2.read_frame(); -// ASSERT_EQ(received_frame->get_identifier(), 0x292u); -// ASSERT_EQ(received_frame->get_data(), 0x1234567890123456u); -// ASSERT_FALSE(bus2.is_frame_ready()); -// CanFrame new_frame(0x293, 0x1234567890123457); -// bus2.write_frame(my_frame); -// bus2.write_frame(new_frame); -// ASSERT_TRUE(bus1.is_frame_ready()); -// ASSERT_FALSE(bus2.is_frame_ready()); -// std::unique_ptr received_frame_1 = bus1.read_frame(); -// ASSERT_TRUE(bus1.is_frame_ready()); -// std::unique_ptr received_frame_2 = bus1.read_frame(); -// ASSERT_FALSE(bus1.is_frame_ready()); -// ASSERT_EQ(received_frame_1->get_identifier(), 0x292u); -// ASSERT_EQ(received_frame_1->get_data(), 0x1234567890123456u); -// ASSERT_EQ(received_frame_2->get_identifier(), 0x293u); -// ASSERT_EQ(received_frame_2->get_data(), 0x1234567890123457u); -// } diff --git a/src/perception/occupancy_cpp/include/occupancy_cpp/StaticOccupancyNode.hpp b/src/perception/occupancy_cpp/include/occupancy_cpp/StaticOccupancyNode.hpp old mode 100755 new mode 100644 index 8f62b3ba4..941e0817b --- a/src/perception/occupancy_cpp/include/occupancy_cpp/StaticOccupancyNode.hpp +++ b/src/perception/occupancy_cpp/include/occupancy_cpp/StaticOccupancyNode.hpp @@ -9,7 +9,6 @@ #pragma once - // Message definitions #include "nav_msgs/msg/occupancy_grid.hpp" #include "rosgraph_msgs/msg/clock.hpp" @@ -34,9 +33,9 @@ using namespace std::chrono_literals; using nav_msgs::msg::OccupancyGrid; +using nova_msgs::msg::Masses; using rosgraph_msgs::msg::Clock; using sensor_msgs::msg::PointCloud2; -// using nova_msgs::msg::Masses; namespace navigator { @@ -50,10 +49,9 @@ namespace navigator virtual ~StaticOccupancyNode(); private: - // Publishers rclcpp::Publisher::SharedPtr occupancy_grid_pub; - // rclcpp::Publisher::SharedPtr masses_pub; + rclcpp::Publisher::SharedPtr masses_pub; // Subscribers rclcpp::Subscription::SharedPtr clock_sub; @@ -69,74 +67,82 @@ namespace navigator void createOccupancyGrid(pcl::PointCloud &cloud); bool initialization_phase = true; - double vehicle_x; - double vehicle_y; - double prev_vehicle_x; - double prev_vehicle_y; - double change_x; - double change_y; - double x_new_low; - double x_new_high; - double y_new_low; - double y_new_high; - double x_old_low; - double x_old_high; - double y_old_low; - double y_old_high; + float vehicle_x; + float vehicle_y; + float prev_vehicle_x; + float prev_vehicle_y; + float change_x; + float change_y; + float x_new_low; + float x_new_high; + float y_new_low; + float y_new_high; + float x_old_low; + float x_old_high; + float y_old_low; + float y_old_high; // There are only two events: 0 = Occupied and 1 = Free. const static int event_num = 2; // Grid size. - const static int grid_size = 128; + const static int GRID_SIZE = 128; - const int SIZE = 64; + const int HALF_SIZE = GRID_SIZE / 2; // Resolution. - constexpr static double res = 1. / 3.; + constexpr static float res = 1. / 3.; // Measurement mass. - constexpr static double meas_mass = 0.95; + constexpr static float meas_mass = 0.95; - // Occupancy measurement. - constexpr static double alpha = 0.9; + // Occupancy measurement. (ALPHA) + constexpr static float decay_factor = 0.9; // Place holders vehicle positions. - constexpr static double vehicle_pos_x = 0; - constexpr static double vehicle_pos_y = 0; - constexpr static double prev_vehicle_pos_x = 0; - constexpr static double prev_vehicle_pos_y = 0; + constexpr static float vehicle_pos_x = 0; + constexpr static float vehicle_pos_y = 0; + constexpr static float prev_vehicle_pos_x = 0; + constexpr static float prev_vehicle_pos_y = 0; // Masses masses_msg; // Array with the DST data. - double meas_grids[event_num][grid_size][grid_size]; + float meas_grids[event_num][GRID_SIZE][GRID_SIZE]; // "Freeness" measurement. - double meas_free[grid_size][grid_size] = {{0}}; + float measured_free[GRID_SIZE][GRID_SIZE] = {{0}}; // Occupancy measurement. - double meas_occ[grid_size][grid_size] = {{0}}; - double prev_free[grid_size][grid_size] = {{0}}; - double prev_occ[grid_size][grid_size] = {{0}}; - double up_free_pred[grid_size][grid_size]; - double up_occ_pred[grid_size][grid_size]; - double up_free[grid_size][grid_size]; - double up_occ[grid_size][grid_size]; + float measured_occ[GRID_SIZE][GRID_SIZE] = {{0}}; + float previous_free[GRID_SIZE][GRID_SIZE] = {{0}}; + float previous_occ[GRID_SIZE][GRID_SIZE] = {{0}}; + float updated_freeP[GRID_SIZE][GRID_SIZE] = {{0}}; + float updated_occP[GRID_SIZE][GRID_SIZE] = {{0}}; + float updated_free[GRID_SIZE][GRID_SIZE] = {{0}}; + float updated_occ[GRID_SIZE][GRID_SIZE] = {{0}}; + + // Masses measurement (probability distribution) + float probabilities[GRID_SIZE][GRID_SIZE] = {{0}}; + float probabilities_plot[GRID_SIZE][GRID_SIZE] = {{0}}; + bool angles[360]; bool first; - //void timer_cb(const ros::TimerEvent &); + // void timer_cb(const ros::TimerEvent &); void transform_listener(); void pointCloudCb(const PointCloud2::SharedPtr msg); void create_DST_grid(pcl::PointCloud &cloud); - void ray_tracing_approximation_x_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive); - void ray_tracing_approximation_y_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive); - int find_nearest(int n, double v, double v0, double vn, double res); + void ray_tracing_approximation_x_increment(int x2, int y2, int flip_x, int flip_y, bool inclusive); + void ray_tracing_approximation_y_increment(int x2, int y2, int flip_x, int flip_y, bool inclusive); + int find_nearest(int num, float value, float min, float max, float res); + void update_previous(); void mass_update(); void update_of(); - std::vector> getGridCellProbabilities(); + void get_mass(); + void plotting(); + std::vector> getGridCellProbabilities(); void publishOccupancyGrid(); void clear(); void fill(std::vector flip); diff --git a/src/perception/occupancy_cpp/src/StaticOccupancyNode.cpp b/src/perception/occupancy_cpp/src/StaticOccupancyNode.cpp index 84dd51edf..27d4ffd55 100755 --- a/src/perception/occupancy_cpp/src/StaticOccupancyNode.cpp +++ b/src/perception/occupancy_cpp/src/StaticOccupancyNode.cpp @@ -12,8 +12,14 @@ using namespace navigator::perception; using namespace std::chrono_literals; +/** + * @brief Constructor for static occupancy node + * Subscribers: CARLA clock, Ground Segmented Pointcloud + * Publishers: Static Occupancy Grid, Masses Grid + */ StaticOccupancyNode::StaticOccupancyNode() : Node("static_occupancy_node") { + //------Subscribers-------// // Subscribe to and use CARLA's clock clock_sub = this->create_subscription( "/clock", 10, @@ -21,12 +27,13 @@ StaticOccupancyNode::StaticOccupancyNode() : Node("static_occupancy_node") { this->clock = *msg; }); pcd_sub = this->create_subscription( - "/lidar/fused", + "/lidar/filtered", 10, std::bind(&StaticOccupancyNode::pointCloudCb, this, std::placeholders::_1)); + //----Publishers-------// occupancy_grid_pub = this->create_publisher("/grid/occupancy/current", 10); - // masses_pub = this->create_publisher("masses", 10); + masses_pub = this->create_publisher("/grid/masses", 10); } StaticOccupancyNode::~StaticOccupancyNode() @@ -35,126 +42,53 @@ StaticOccupancyNode::~StaticOccupancyNode() } /** - * @brief Each time that raw LiDAR is received, remove the ground points and publish the filtered version. + * @brief Each time that raw LiDAR pcl is received: + * 1. Convert to pcl::PointCloud (x, y, z, intensity), keep in mind this reverses rows and columns? + * 2. Fills and ray traces static occupancy grid * - * @param raw_cloud The unfiltered LiDAR point cloud + * @param msg The LiDAR point cloud previously ground segmented */ void StaticOccupancyNode::pointCloudCb(PointCloud2::SharedPtr msg) { - /* - PC processing. - */ - - double centerpoint_x = 64; - double centerpoint_y = 64; - double xstart = -1; - double ystart = -1; - double xend = -1; - double yend = -1; - // Converts the PCL ros message using pcl_conversions. pcl::PointCloud cloud; pcl::fromROSMsg(*msg, cloud); // 1. Convert new measurement into a DST grid. createOccupancyGrid(cloud); - printf("Up_Occ: %d, Up_Free: %d\n", up_occ[50][50], up_free[50][50]); - printf("Meas_Occ: %d\n", meas_occ[50][50]); - printf("Prev_Occ: %d, Prev_Free: %d\n", prev_occ[50][50], prev_free[50][50]); - - change_x = 0.0; // TODO: Remove or fix the "change" variables. - change_y = 0.0; - - x_new_low = change_x - 64 * res; - x_new_high = change_x + 64 * res; - y_new_low = change_y - 64 * res; - y_new_high = change_y + 64 * res; - - if (initialization_phase == false) - { - if ((x_new_low >= x_old_low) && (x_old_high >= x_new_low)) - { - xstart = x_new_low; - xend = x_old_high; - } - - if ((y_new_low >= y_old_low) && (y_old_high >= y_new_low)) - { - ystart = y_new_low; - yend = y_old_high; - } - - if ((x_new_low < x_old_low) && (x_new_high >= x_old_low)) - { - xstart = x_old_low; - xend = x_new_high; - } - - if ((y_new_low < y_old_low) && (y_new_high >= y_old_low)) - { - ystart = y_old_low; - yend = y_new_high; - } - - if ((xstart != -1) && (ystart != -1)) - { - - int indx_nl = find_nearest(grid_size, xstart, x_new_low, x_new_high, res); - int indx_nh = find_nearest(grid_size, xend, x_new_low, x_new_high, res); - int indy_nl = find_nearest(grid_size, ystart, y_new_low, y_new_high, res); - int indy_nh = find_nearest(grid_size, yend, y_new_low, y_new_high, res); - - int indx_ol = find_nearest(grid_size, xstart, x_old_low, x_old_high, res); - int indx_oh = find_nearest(grid_size, xend, x_old_low, x_old_high, res); - int indy_ol = find_nearest(grid_size, ystart, y_old_low, y_old_high, res); - int indy_oh = find_nearest(grid_size, yend, y_old_low, y_old_high, res); - - for (unsigned int i = 0; i < indx_oh - indx_ol + 1; i++) - { - for (unsigned int j = 0; j < indy_oh - indy_ol + 1; j++) - { - prev_free[indx_nl + i][indy_nl + j] = up_free[indx_ol + i][indy_ol + j]; - prev_occ[indx_nl + i][indy_nl + j] = up_occ[indx_ol + i][indy_ol + j]; - } - } - } - } + // 2. Updates previous grid with updated grid values (important in cases of variable grid size) + update_previous(); + // 3. Add decayed region (previous grid) to the updated grid mass_update(); - // get_mass(); + + // 4. Publish static occupancy grid and mass grid publishOccupancyGrid(); - clear(); - initialization_phase = false; - x_old_low = x_new_low; - x_old_high = x_new_high; - y_old_low = y_new_low; - y_old_high = y_new_high; + // 5. Clear current measured grid + clear(); } /** * @brief Returns a grid using Dempster-Shafer Theory (DST) + * 1. Ray-traces free space towards recorded points (occupied space) + * 2. Fills the rest of the grid with free space using same ray-tracing algorithms (can combine steps 1 and 2?) + * 3. Adds occupied space representing the vehicle * * @param cloud * @return pcl::PointCloud */ void StaticOccupancyNode::createOccupancyGrid(pcl::PointCloud &cloud) { - // The grid is created in three stages. - - // Initialize DST grid - // pcl::PointCloud grid; - - // 1. Add occupied cells to the DST grid + // 1. Ray traces towards occupied spaces add_points_to_the_DST(cloud); - // 2. Identify free space in the DST grid. + + // 2. Ray traces rest of grid to fill with empty space add_free_spaces_to_the_DST(); // 3. Add an ego vehicle mask to the grid. - addEgoMask(); - - //return grid; + // addEgoMask(); } /** @@ -165,23 +99,28 @@ void StaticOccupancyNode::createOccupancyGrid(pcl::PointCloud &c */ void StaticOccupancyNode::add_points_to_the_DST(pcl::PointCloud &cloud) { - std::printf("Adding %i points to the DST.\n", cloud.size()); + // std::printf("Adding %i points to the DST.\n\n", cloud.size()); for (size_t i = 0; i < cloud.size(); i++) { + // Dimensions for X & Y [-64 -> 64 (HALF_SiZE)] + + // Record occupancy value for the corresponding point in the pcl, nearest index int x = (int)(cloud[i].x / res); int y = (int)(cloud[i].y / res); - double z = cloud.points[i].z; - // Ignores points above a certain height? + float z = cloud[i].z; + + // Ignores points above a certain height if (z * (-1) > 0.5) { std::printf("Point was above max height, skipping.\n"); continue; } - else if (x < -1 * SIZE && y < -1 * SIZE && x >= SIZE && y >= SIZE) + + if (x < (-1 * HALF_SIZE) || y < (-1 * HALF_SIZE) || x >= HALF_SIZE || y >= HALF_SIZE) { - std::printf("Point was outside grid boundaries, skipping.\n"); + // std::printf("Point was outside grid boundaries, skipping.\n"); continue; } @@ -189,62 +128,59 @@ void StaticOccupancyNode::add_points_to_the_DST(pcl::PointCloud // Angles vector contians which angles from 0 deg to 360 deg have been represented. // It is used to identify free spaces for angles not covered by PC or out of range points. - if (cloud.points[i].y > 0 && cloud.points[i].x < 0) + if (cloud[i].y > 0 && cloud[i].x < 0) { - angle = 180 - (int)(atan(std::abs(cloud.points[i].y) / std::abs(cloud.points[i].x)) * 180.0 / M_PI); + angle = 180 - (int)(atan(std::abs(cloud[i].y) / std::abs(cloud[i].x)) * 180.0 / M_PI); } - else if (cloud.points[i].y < 0 && cloud.points[i].x < 0) + else if (cloud[i].y < 0 && cloud[i].x < 0) { - angle = 180 + (int)(atan(std::abs(cloud.points[i].y) / std::abs(cloud.points[i].x)) * 180.0 / M_PI); + angle = 180 + (int)(atan(std::abs(cloud[i].y) / std::abs(cloud[i].x)) * 180.0 / M_PI); } - else if (cloud.points[i].y < 0 && cloud.points[i].x > 0) + else if (cloud[i].y < 0 && cloud[i].x > 0) { - angle = 360 - (int)(atan(std::abs(cloud.points[i].y) / std::abs(cloud.points[i].x)) * 180.0 / M_PI); + angle = 360 - (int)(atan(std::abs(cloud[i].y) / std::abs(cloud[i].x)) * 180.0 / M_PI); } else { - angle = (int)(atan(std::abs(cloud.points[i].y) / std::abs(cloud.points[i].x)) * 180.0 / M_PI); + angle = (int)(atan(std::abs(cloud[i].y) / std::abs(cloud[i].x)) * 180.0 / M_PI); } angles[angle] = true; - double slope = (double)(y) / (x); + + float slope = (float)(y) / (x); // ray tracing from origin to point, identifies free space using Bresenhaum's line algo if (slope > 0 && slope <= 1 && x > 0) { - ray_tracing_approximation_y_increment(0, 0, x, y, 1, 1, false); + ray_tracing_approximation_y_increment(x, y, 1, 1, false); } else if (slope > 1 && x > 0) { - ray_tracing_approximation_x_increment(0, 0, x, y, 1, 1, false); + ray_tracing_approximation_x_increment(x, y, 1, 1, false); } else if (slope < 0 && slope >= -1 && x > 0) { - ray_tracing_approximation_y_increment(0, 0, x, (-1) * y, 1, -1, false); + ray_tracing_approximation_y_increment(x, (-1) * y, 1, -1, false); } else if (slope < -1 && x > 0) { - ray_tracing_approximation_x_increment(0, 0, x, (-1) * y, 1, -1, false); + ray_tracing_approximation_x_increment(x, (-1) * y, 1, -1, false); } else if (slope > 1 && x < 0) { - ray_tracing_approximation_x_increment(0, 0, (-1) * x, (-1) * y, -1, -1, false); + ray_tracing_approximation_x_increment((-1) * x, (-1) * y, -1, -1, false); } else if (slope > 0 && slope <= 1 && x < 0) { - ray_tracing_approximation_y_increment(0, 0, (-1) * x, (-1) * y, -1, -1, false); + ray_tracing_approximation_y_increment((-1) * x, (-1) * y, -1, -1, false); } else if (slope < 0 && slope >= -1 && x < 0) { - ray_tracing_approximation_y_increment(0, 0, (-1) * x, y, -1, 1, false); + ray_tracing_approximation_y_increment((-1) * x, y, -1, 1, false); } else if (slope < -1 && x < 0) { - ray_tracing_approximation_x_increment(0, 0, (-1) * x, y, -1, 1, false); - } - else { - printf("Did not match a case.\n"); - //printf("X: %f, Y: %f, SLOPE %f\n", x, y, slope); + ray_tracing_approximation_x_increment((-1) * x, y, -1, 1, false); } } } @@ -254,73 +190,73 @@ void StaticOccupancyNode::add_points_to_the_DST(pcl::PointCloud */ void StaticOccupancyNode::add_free_spaces_to_the_DST() { - double i = 0.0; - float ang = 0.0f; + float i = 0.0; + float angle = 0.0f; // fills free spaces, not efficient? for (unsigned int i = 0; i < 3600; i++) { - ang = (i * 0.1f); + angle = (i * 0.1f); - if (angles[(int)(ang)] == false) + if (angles[(int)(angle)] == false) { int x, y; - if (ang > 0.0f && ang <= 45.0f) + if (angle > 0.0f && angle <= 45.0f) { x = 64; - y = (int)(tan(ang * M_PI / 180.0f) * x); + y = (int)(tan(angle * M_PI / 180.0f) * x); } - else if (ang > 45.0f && ang < 90.0f) + else if (angle > 45.0f && angle < 90.0f) { y = 64; - x = (int)(y / tan(ang * M_PI / 180.0f)); + x = (int)(y / tan(angle * M_PI / 180.0f)); } - else if (ang > 90.0f && ang <= 135.0f) + else if (angle > 90.0f && angle <= 135.0f) { y = 64; - x = (int)(y / tan((ang - 180.0f) * M_PI / 180.0f)); + x = (int)(y / tan((angle - 180.0f) * M_PI / 180.0f)); } - else if (ang > 135.0f && ang < 180.0f) + else if (angle > 135.0f && angle < 180.0f) { x = -64; - y = (int)(tan((ang - 180.0) * M_PI / 180.0f) * x); + y = (int)(tan((angle - 180.0) * M_PI / 180.0f) * x); } - else if (ang > 180.0f && ang <= 225.0f) + else if (angle > 180.0f && angle <= 225.0f) { x = -64; - y = (int)(tan((ang - 180.0f) * M_PI / 180.0f) * x); + y = (int)(tan((angle - 180.0f) * M_PI / 180.0f) * x); } - else if (ang > 225.0f && ang < 270.0f) + else if (angle > 225.0f && angle < 270.0f) { y = -64; - x = (int)(y / tan((ang - 180.0f) * M_PI / 180.0f)); + x = (int)(y / tan((angle - 180.0f) * M_PI / 180.0f)); } - else if (ang > 270.0f && ang <= 315.0f) + else if (angle > 270.0f && angle <= 315.0f) { y = -64; - x = (int)(y / tan((ang - 360.0f) * M_PI / 180.0f)); + x = (int)(y / tan((angle - 360.0f) * M_PI / 180.0f)); } - else if (ang > 315.0f && ang < 360.0f) + else if (angle > 315.0f && angle < 360.0f) { x = 64; - y = (int)(tan((ang - 360.0f) * M_PI / 180.0f) * x); + y = (int)(tan((angle - 360.0f) * M_PI / 180.0f) * x); } - else if (ang == 0.0f || ang == 360.0f) + else if (angle == 0.0f || angle == 360.0f) { ray_tracing_horizontal(64); continue; } - else if (ang == 90.0f) + else if (angle == 90.0f) { ray_tracing_vertical(64); continue; } - else if (ang == 180.0f) + else if (angle == 180.0f) { ray_tracing_horizontal_n(-64); continue; } - else if (ang == 270.0f) + else if (angle == 270.0f) { ray_tracing_vertical_n(-64); continue; @@ -328,43 +264,43 @@ void StaticOccupancyNode::add_free_spaces_to_the_DST() if (x >= -64 && y >= -64 && x <= 64 && y <= 64) { + float slope = (float)(y) / (x); - double slope = (double)(y) / (x); if (slope > 0 && slope <= 1 && x > 0) { - ray_tracing_approximation_y_increment(0, 0, x, y, 1, 1, true); + ray_tracing_approximation_y_increment(x, y, 1, 1, true); } else if (slope > 1 && x > 0) { - ray_tracing_approximation_x_increment(0, 0, x, y, 1, 1, true); + ray_tracing_approximation_x_increment(x, y, 1, 1, true); } else if (slope < 0 && slope >= -1 && x > 0) { - ray_tracing_approximation_y_increment(0, 0, x, (-1) * y, 1, -1, true); + ray_tracing_approximation_y_increment(x, (-1) * y, 1, -1, true); } else if (slope < -1 && x > 0) { - ray_tracing_approximation_x_increment(0, 0, x, (-1) * y, 1, -1, true); + ray_tracing_approximation_x_increment(x, (-1) * y, 1, -1, true); } else if (slope > 1 && x < 0) { - ray_tracing_approximation_x_increment(0, 0, (-1) * x, (-1) * y, -1, -1, true); + ray_tracing_approximation_x_increment((-1) * x, (-1) * y, -1, -1, true); } else if (slope > 0 && slope <= 1 && x < 0) { - ray_tracing_approximation_y_increment(0, 0, (-1) * x, (-1) * y, -1, -1, true); + ray_tracing_approximation_y_increment((-1) * x, (-1) * y, -1, -1, true); } else if (slope < 0 && slope >= -1 && x < 0) { - ray_tracing_approximation_y_increment(0, 0, (-1) * x, y, -1, 1, true); + ray_tracing_approximation_y_increment((-1) * x, y, -1, 1, true); } else if (slope < -1 && x < 0) { - ray_tracing_approximation_x_increment(0, 0, (-1) * x, y, -1, 1, true); + ray_tracing_approximation_x_increment((-1) * x, y, -1, 1, true); } } } - angles[(int)(ang)] = false; + angles[(int)(angle)] = false; } } @@ -375,12 +311,12 @@ void StaticOccupancyNode::add_free_spaces_to_the_DST() void StaticOccupancyNode::addEgoMask() { // Vehicle shape. - for (unsigned int j = 60; j < 68; j++) + for (unsigned int i = 60; i < 68; i++) { - for (unsigned int i = 62; i < 67; i++) + for (unsigned int j = 62; j < 67; j++) { - meas_occ[j][i] = 1.0; - meas_free[j][i] = 0.0; + measured_occ[i][j] = 1.0; + measured_free[i][j] = 0.0; } } } @@ -389,74 +325,183 @@ void StaticOccupancyNode::addEgoMask() void StaticOccupancyNode::publishOccupancyGrid() { + //--Occupancy Grid--// OccupancyGrid msg; msg.header.stamp = this->clock.clock; msg.header.frame_id = "base_link"; // TODO: Make sure the frame is the correct one. msg.info.resolution = res; - msg.info.width = grid_size; - msg.info.height = grid_size; + msg.info.width = GRID_SIZE; + msg.info.height = GRID_SIZE; msg.info.origin.position.z = 0.2; msg.info.origin.position.x = -64.0 * (1. / 3.); msg.info.origin.position.y = -64.0 * (1. / 3.); - // masses_msg.width = grid_size; - // masses_msg.height = grid_size; + //-----------------// - auto probabilites = getGridCellProbabilities(); + //--Masses--// + Masses masses_msg; + masses_msg.occ.clear(); + masses_msg.free.clear(); + masses_msg.width = GRID_SIZE; + masses_msg.height = GRID_SIZE; + //----------// - for (unsigned int i = 0; i < grid_size; i++) + auto probabilities = getGridCellProbabilities(); + + for (int i = 0; i < GRID_SIZE; i++) { - for (unsigned int j = 0; j < grid_size; j++) + for (int j = 0; j < GRID_SIZE; j++) { - msg.data.push_back(probabilites.at(i).at(j)); + msg.data.push_back(100 * probabilities.at(j).at(i)); + masses_msg.occ.push_back(updated_occ[i][j]); + masses_msg.free.push_back(updated_free[i][j]); } } occupancy_grid_pub->publish(msg); - // masses_pub->publish(masses_msg); + masses_pub->publish(masses_msg); } +void StaticOccupancyNode::update_previous() +{ + for (unsigned int i = 0; i < GRID_SIZE; i++) + { + for (unsigned int j = 0; j < GRID_SIZE; j++) + { + previous_free[i][j] = updated_free[i][j]; + previous_occ[i][j] = updated_occ[i][j]; + } + } + + //--------CODE FOR VARIABLE INPUT GRID SIZE BELOW----------// + + // float xstart = -1; + // float ystart = -1; + // float xend = -1; + // float yend = -1; + + // change_x = 0.0; // TODO: Remove or fix the "change" variables. + // change_y = 0.0; + + // x_new_low = change_x - 64 * res; + // x_new_high = change_x + 64 * res; + // y_new_low = change_y - 64 * res; + // y_new_high = change_y + 64 * res; + + // if (initialization_phase == false) + // { + + // if ((x_new_low >= x_old_low) && (x_old_high >= x_new_low)) + // { + // xstart = x_new_low; + // xend = x_old_high; } + + // if ((y_new_low >= y_old_low) && (y_old_high >= y_new_low)) + // { + // ystart = y_new_low; + // yend = y_old_high; } + + // if ((x_new_low < x_old_low) && (x_new_high >= x_old_low)) + // { + // xstart = x_old_low; + // xend = x_new_high; } + + // if ((y_new_low < y_old_low) && (y_new_high >= y_old_low)) + // { + // ystart = y_old_low; + // yend = y_new_high; } + + // if ((xstart != -1) && (ystart != -1)) + // { + + // /** + // * NL = New Low, OH = Old High + // */ + // //x + // int index_xNL = find_nearest(GRID_SIZE, xstart, x_new_low, x_new_high, res); + // int index_xNH = find_nearest(GRID_SIZE, xend, x_new_low, x_new_high, res); + // int index_xOL = find_nearest(GRID_SIZE, xstart, x_old_low, x_old_high, res); + // int index_xOH = find_nearest(GRID_SIZE, xend, x_old_low, x_old_high, res); + // //y + // int index_yNL = find_nearest(GRID_SIZE, ystart, y_new_low, y_new_high, res); + // int index_yNH = find_nearest(GRID_SIZE, yend, y_new_low, y_new_high, res); + // int index_yOL = find_nearest(GRID_SIZE, ystart, y_old_low, y_old_high, res); + // int index_yOH = find_nearest(GRID_SIZE, yend, y_old_low, y_old_high, res); + + // printf("index_xNL: %i, index_xNH: %i, index_xOL: %i, index_xOH: %i\n\n", index_xNL, index_xNH, index_xOL, index_xOH); + + // for (unsigned int i = 0; i < index_xOH - index_xOL + 1; i++) + // { + // for (unsigned int j = 0; j < index_yOH - index_yOL + 1; j++) + // { + // previous_free[index_xNL + i][index_yNL + j] = updated_free[index_xOL + i][index_yOL + j]; + // previous_occ[index_xNL + i][index_yNL + j] = updated_occ[index_xOL + i][index_yOL + j]; + // } + // } + // } + // } + + // initialization_phase = false; + // x_old_low = x_new_low; + // x_old_high = x_new_high; + // y_old_low = y_new_low; + // y_old_high = y_new_high; + + //----------END OF CODE------------// +} + +/** + * @brief: Updates current grids with previous grid values plus a decay + */ void StaticOccupancyNode::mass_update() { - for (unsigned int i = 0; i < grid_size; i++) + for (unsigned int i = 0; i < GRID_SIZE; i++) { - for (unsigned int j = 0; j < grid_size; j++) + for (unsigned int j = 0; j < GRID_SIZE; j++) { - up_occ_pred[i][j] = std::min(alpha * prev_occ[i][j], 1.0 - prev_free[i][j]); - up_free_pred[i][j] = std::min(alpha * prev_free[i][j], 1.0 - prev_occ[i][j]); + updated_occP[i][j] = std::min(decay_factor * previous_occ[i][j], 1.0f - previous_free[i][j]); + updated_freeP[i][j] = std::min(decay_factor * previous_free[i][j], 1.0f - previous_occ[i][j]); } } - // Combine measurement nad prediction to form posterior occupied and free masses. + // Combine measurement and prediction to form posterior occupied and free masses. update_of(); } +// updates probabilities using a bayes filter. Takes into account measured probabilities and predicted probability values. void StaticOccupancyNode::update_of() { - for (unsigned int i = 0; i < grid_size; i++) + for (unsigned int i = 0; i < GRID_SIZE; i++) { - for (unsigned int j = 0; j < grid_size; j++) + for (unsigned int j = 0; j < GRID_SIZE; j++) { - double unknown_pred = 1.0 - up_free_pred[i][j] - up_occ_pred[i][j]; - double meas_cell_unknown = 1.0 - meas_free[i][j] - meas_occ[i][j]; - double k_value = up_free_pred[i][j] * meas_occ[i][j] + up_occ_pred[i][j] * meas_free[i][j]; - up_occ[i][j] = (up_occ_pred[i][j] * meas_cell_unknown + unknown_pred * meas_occ[i][j] + up_occ_pred[i][j] * meas_occ[i][j]) / (1.0 - k_value); - up_free[i][j] = (up_free_pred[i][j] * meas_cell_unknown + unknown_pred * meas_free[i][j] + up_free_pred[i][j] * meas_free[i][j]) / (1.0 - k_value); + // probability of cell being unknown + float unknown_pred = 1.0 - updated_freeP[i][j] - updated_occP[i][j]; + + // probabilityy of measured cell being unknown + float measured_cell_unknown = 1.0 - measured_free[i][j] - measured_occ[i][j]; + + // normalizing factor, ensures probabilities for occupancy/free add up to 1 + float k_value = updated_freeP[i][j] * measured_occ[i][j] + updated_occP[i][j] * measured_free[i][j]; + + updated_occ[i][j] = (updated_occP[i][j] * measured_cell_unknown + unknown_pred * measured_occ[i][j] + updated_occP[i][j] * measured_occ[i][j]) / (1.0f - k_value); + updated_free[i][j] = (updated_freeP[i][j] * measured_cell_unknown + unknown_pred * measured_free[i][j] + updated_freeP[i][j] * measured_free[i][j]) / (1.0f - k_value); } } } /** - * @brief + * @brief Gets the average of the updated occupancy and updated free values and adds to a cell_probabilities * + * @return Returns a vector of grid cell probabilities used to fill the OccupancyGrid message */ -std::vector> StaticOccupancyNode::getGridCellProbabilities() +std::vector> StaticOccupancyNode::getGridCellProbabilities() { - std::vector> cell_probabilities; - for (unsigned int i = 0; i < grid_size; i++) + std::vector> cell_probabilities; + for (unsigned int i = 0; i < GRID_SIZE; i++) { - std::vector row; - for (unsigned int j = 0; j < grid_size; j++) + std::vector row; + for (unsigned int j = 0; j < GRID_SIZE; j++) { - double probability = (0.5 * up_occ[i][j] + 0.5 * (1.0 - up_free[i][j])); + float probability = (0.5 * updated_occ[i][j] + 0.5 * (1.0 - updated_free[i][j])); row.push_back(probability); } cell_probabilities.push_back(row); @@ -465,28 +510,30 @@ std::vector> StaticOccupancyNode::getGridCellProbabilities() return cell_probabilities; } -int StaticOccupancyNode::find_nearest(int n, double v, double v0, double vn, double res) +int StaticOccupancyNode::find_nearest(int num, float value, float min, float max, float res) { - int idx = std::floor(n * (v - v0 + res / 2.) / (vn - v0 + res)); - return idx; + int index = std::floor(num * (value - min + res / 2.) / (max - min + res)); + return index; } //------------------------------------------------// //-------------RAY TRACING HELPERS----------------// - -void StaticOccupancyNode::ray_tracing_approximation_y_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive) +void StaticOccupancyNode::ray_tracing_approximation_y_increment(int x2, int y2, int flip_x, int flip_y, bool inclusive) { + int x1 = 0, y1 = 0; + int slope = 2 * (y2 - y1); int slope_error = slope - (x2 - x1); int x_sample, y_sample; for (int x = x1, y = y1; x < x2; x++) { - if (meas_occ[flip_x * x + 64][flip_y * y + 64] == meas_mass) + // checks if the point is occupied + if (measured_occ[flip_x * x + 64][flip_y * y + 64] == meas_mass) { break; } - meas_free[flip_x * x + 64][flip_y * y + 64] = meas_mass; + measured_free[flip_x * x + 64][flip_y * y + 64] = meas_mass; slope_error += slope; if (slope_error >= 0) @@ -496,26 +543,32 @@ void StaticOccupancyNode::ray_tracing_approximation_y_increment(int x1, int y1, } } + // if the point ray-traced to is occupied if (inclusive == false) { - meas_occ[flip_x * x2 + 64][flip_y * y2 + 64] = meas_mass; - meas_free[flip_x * x2 + 64][flip_y * y2 + 64] = 0.0; + int x_coordinate = flip_x * x2 + 64; + int y_coordinate = flip_y * y2 + 64; + measured_occ[x_coordinate][y_coordinate] = meas_mass; + measured_free[x_coordinate][y_coordinate] = 0.0; } } -void StaticOccupancyNode::ray_tracing_approximation_x_increment(int x1, int y1, int x2, int y2, int flip_x, int flip_y, bool inclusive) +void StaticOccupancyNode::ray_tracing_approximation_x_increment(int x2, int y2, int flip_x, int flip_y, bool inclusive) { + int x1 = 0, y1 = 0; + int slope = 2 * (x2 - x1); int slope_error = slope - (y2 - y1); int x_sample, y_sample; for (int x = x1, y = y1; y < y2; y++) { - if (meas_occ[flip_x * x + 64][flip_y * y + 64] == meas_mass) + // checks if the point is occupied + if (measured_occ[flip_x * x + 64][flip_y * y + 64] == meas_mass) { break; } - meas_free[flip_x * x + 64][flip_y * y + 64] = meas_mass; + measured_free[flip_x * x + 64][flip_y * y + 64] = meas_mass; slope_error += slope; if (slope_error >= 0) @@ -525,14 +578,18 @@ void StaticOccupancyNode::ray_tracing_approximation_x_increment(int x1, int y1, } } + // if the point ray-traced to is occupied if (inclusive == false) { - meas_occ[flip_x * x2 + 64][flip_y * y2 + 64] = meas_mass; - meas_free[flip_x * x2 + 64][flip_y * y2 + 64] = 0.0; + int x_coordinate = flip_x * x2 + 64; + int y_coordinate = flip_y * y2 + 64; + measured_occ[x_coordinate][y_coordinate] = meas_mass; + measured_free[x_coordinate][y_coordinate] = 0.0; } } -void StaticOccupancyNode::ray_tracing_horizontal(int x2) +// VERTICLE + +void StaticOccupancyNode::ray_tracing_vertical(int x2) { int x1 = 0; int y1 = 0; @@ -540,18 +597,21 @@ void StaticOccupancyNode::ray_tracing_horizontal(int x2) for (int x = x1; x <= x2; x++) { - if (meas_occ[x + 64][64] == meas_mass) + // checks if the point is occupied + if (measured_occ[64][x + 64] == meas_mass) { + printf("BROKE! VERTICAL + \n\n"); break; } - meas_free[x + 64][64] = meas_mass; + measured_free[x + 64][64] = meas_mass; } - meas_free[x2 + 64][64] = 0.0; + measured_free[x2 + 64][64] = 0.0; } -void StaticOccupancyNode::ray_tracing_horizontal_n(int x1) +// VERTICLE - +void StaticOccupancyNode::ray_tracing_vertical_n(int x1) { int x2 = 0; int y2 = 0; @@ -559,18 +619,20 @@ void StaticOccupancyNode::ray_tracing_horizontal_n(int x1) for (int x = x1; x <= x2; x++) { - if (meas_occ[x + 64][64] == meas_mass) + if (measured_occ[64][x + 64] == meas_mass) { + printf("BROKE! VERTICAL - \n\n"); break; } - meas_free[x + 64][64] = meas_mass; + measured_free[x + 64][64] = meas_mass; } - meas_free[x2 + 64][64] = 0.0; + measured_free[x2 + 64][64] = 0.0; } -void StaticOccupancyNode::ray_tracing_vertical(int y2) +// HORIZONTAL + +void StaticOccupancyNode::ray_tracing_horizontal(int y2) { int x1 = 0; int y1 = 0; @@ -578,15 +640,17 @@ void StaticOccupancyNode::ray_tracing_vertical(int y2) for (int y = y1; y <= y2; y++) { - if (meas_occ[64][y + 64] == meas_mass) + if (measured_occ[64][y + 64] == meas_mass) { + printf("BROKE! HORIZONTAL + \n\n"); break; } - meas_free[64][y + 64] = meas_mass; + measured_free[64][y + 64] = meas_mass; } } -void StaticOccupancyNode::ray_tracing_vertical_n(int y1) +// HORIZONTAL - +void StaticOccupancyNode::ray_tracing_horizontal_n(int y1) { int x1 = 0; int y2 = 0; @@ -594,24 +658,26 @@ void StaticOccupancyNode::ray_tracing_vertical_n(int y1) for (int y = y1; y <= y2; y++) { - if (meas_occ[64][y + 64] == meas_mass) + if ( + measured_occ[64][y + 64] == meas_mass) { + printf("BROKE! HORIZONTAL - \n\n"); break; } - meas_free[64][y + 64] = meas_mass; + measured_free[64][y + 64] = meas_mass; } - meas_free[64][y2 + 64] = 0.0; + measured_free[64][y2 + 64] = 0.0; } void StaticOccupancyNode::clear() { - for (unsigned int i = 0; i < grid_size; i++) + for (unsigned int i = 0; i < GRID_SIZE; i++) { - for (unsigned int j = 0; j < grid_size; j++) + for (unsigned int j = 0; j < GRID_SIZE; j++) { - meas_occ[i][j] = 0.0; - meas_free[i][j] = 0.0; + measured_occ[i][j] = 0.0; + measured_free[i][j] = 0.0; } } } diff --git a/src/perception/mapping/CMakeLists.txt b/src/perception/prednet_inference/CMakeLists.txt similarity index 86% rename from src/perception/mapping/CMakeLists.txt rename to src/perception/prednet_inference/CMakeLists.txt index 8bb167d12..75be30dc4 100755 --- a/src/perception/mapping/CMakeLists.txt +++ b/src/perception/prednet_inference/CMakeLists.txt @@ -14,7 +14,9 @@ cmake_minimum_required(VERSION 3.5) get_filename_component(directory_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${directory_name}) - +find_package(PCL REQUIRED) +find_package(pcl_ros REQUIRED) +include_directories(${OCTOMAP_INCLUDE_DIRS}) # target_link_libraries(${OCTOMAP_LIBRARIES}) find_package(nova_auto_package REQUIRED) diff --git a/src/perception/prednet_inference/package.xml b/src/perception/prednet_inference/package.xml new file mode 100755 index 000000000..b83868355 --- /dev/null +++ b/src/perception/prednet_inference/package.xml @@ -0,0 +1,27 @@ + + + + prednet_inference + 1.0.0 + Nodes for making future dst-grid predictions. + Nova + MIT + + nova_auto_package + + rclpy + ros2_numpy + numpy + time + rosgraph_msgs + std_msgs + nav_msgs + nova_msgs + torch + sensor_msgs + + + + ament_python + + diff --git a/src/perception/prednet_inference/predictionTest/original_5.png b/src/perception/prednet_inference/predictionTest/original_5.png new file mode 100644 index 000000000..a87c393e1 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/original_5.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_0.png b/src/perception/prednet_inference/predictionTest/prediction_example_0.png new file mode 100644 index 000000000..698057210 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_0.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_1.png b/src/perception/prednet_inference/predictionTest/prediction_example_1.png new file mode 100644 index 000000000..08859925b Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_1.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_10.png b/src/perception/prednet_inference/predictionTest/prediction_example_10.png new file mode 100644 index 000000000..72913aeb4 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_10.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_11.png b/src/perception/prednet_inference/predictionTest/prediction_example_11.png new file mode 100644 index 000000000..c16f1b1fe Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_11.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_12.png b/src/perception/prednet_inference/predictionTest/prediction_example_12.png new file mode 100644 index 000000000..cf060a0aa Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_12.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_13.png b/src/perception/prednet_inference/predictionTest/prediction_example_13.png new file mode 100644 index 000000000..bf23ac735 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_13.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_14.png b/src/perception/prednet_inference/predictionTest/prediction_example_14.png new file mode 100644 index 000000000..f4476de5e Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_14.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_15.png b/src/perception/prednet_inference/predictionTest/prediction_example_15.png new file mode 100644 index 000000000..681c0940f Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_15.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_16.png b/src/perception/prednet_inference/predictionTest/prediction_example_16.png new file mode 100644 index 000000000..2391994ae Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_16.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_17.png b/src/perception/prednet_inference/predictionTest/prediction_example_17.png new file mode 100644 index 000000000..d57a9c7a0 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_17.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_18.png b/src/perception/prednet_inference/predictionTest/prediction_example_18.png new file mode 100644 index 000000000..46f2a1e0b Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_18.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_19.png b/src/perception/prednet_inference/predictionTest/prediction_example_19.png new file mode 100644 index 000000000..06e5def2e Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_19.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_2.png b/src/perception/prednet_inference/predictionTest/prediction_example_2.png new file mode 100644 index 000000000..d6902842c Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_2.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_3.png b/src/perception/prednet_inference/predictionTest/prediction_example_3.png new file mode 100644 index 000000000..f11050d3e Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_3.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_4.png b/src/perception/prednet_inference/predictionTest/prediction_example_4.png new file mode 100644 index 000000000..27bc37caf Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_4.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_5.png b/src/perception/prednet_inference/predictionTest/prediction_example_5.png new file mode 100644 index 000000000..c771f97ea Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_5.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_6.png b/src/perception/prednet_inference/predictionTest/prediction_example_6.png new file mode 100644 index 000000000..dc60e5870 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_6.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_7.png b/src/perception/prednet_inference/predictionTest/prediction_example_7.png new file mode 100644 index 000000000..352b1d813 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_7.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_8.png b/src/perception/prednet_inference/predictionTest/prediction_example_8.png new file mode 100644 index 000000000..bfccbb07d Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_8.png differ diff --git a/src/perception/prednet_inference/predictionTest/prediction_example_9.png b/src/perception/prednet_inference/predictionTest/prediction_example_9.png new file mode 100644 index 000000000..92e65ffc8 Binary files /dev/null and b/src/perception/prednet_inference/predictionTest/prediction_example_9.png differ diff --git a/src/perception/prednet_inference/prednet_inference/__init__.py b/src/perception/prednet_inference/prednet_inference/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/src/perception/prednet_inference/prednet_inference/prednet_inference_node.py b/src/perception/prednet_inference/prednet_inference/prednet_inference_node.py new file mode 100755 index 000000000..d23afb35e --- /dev/null +++ b/src/perception/prednet_inference/prednet_inference/prednet_inference_node.py @@ -0,0 +1,333 @@ +''' +Package: sensor_processing + File: lidar_processing_node.py + Author: Will Heitman (w at heit dot mn) + +Node to filter and process raw LiDAR pointclouds + +This node specifically deals with quirks with the +CARLA simulator. Namely, synching issues mean that +raw LiDAR streams "flicker" from left-sided PCDs +to right-sided ones. This node first merges +these left- and right-sided PCDs into a complete +cloud before cutting out points near the car. +''' +# https://1drv.ms/v/s!An_6l1bJUIotjlN-qg-uqKdIORgC?e=s5RDv6 + +import rclpy +import ros2_numpy as rnp +import numpy as np +from rclpy.node import Node +import time +import copy + +from threading import Thread +from array import array as Array + + +# Message definitions +from rosgraph_msgs.msg import Clock +from std_msgs.msg import Float32 +from sensor_msgs.msg import PointCloud2 + +from nav_msgs.msg import OccupancyGrid +from nova_msgs.msg import Masses +from nova_msgs.msg import Egma + + +import torch + + +import matplotlib.pyplot as plt + + +class PredNetNode(Node): + + def __init__(self): + super().__init__('prednet_inference_node') + + # Subcribes to masses + self.masses_sub = self.create_subscription( + Masses, '/grid/masses', self.masses_callback, 10) + # Subscribes to clock for headers + self.clock_sub = self.create_subscription( + Clock, '/clock', self.clock_cb, 10) + # Subscribes to timer in order to make predictions at a constant rate + self.timer = self.create_timer(0.1, self.makePrediction) + + # Instantiates publisher + self.pred_all_pub = self.create_publisher( + Egma, '/grid/predictions', 10) + self.prednet_combined_pub = self.create_publisher( + OccupancyGrid, '/grid/predictions_combined', 10) + + # Stores the past 0.5 seconds of occupancy grids + self.history_m = [] + + # Message to be published + self.prediction_msg = Egma() + + # Whether the required history has been obtained + self.data_acquired = False + + # Amount of grids that have been made + self.time = 0 + + self.frameRate = 10 + + # Time for when to accept the next grid + self.lastAccepted = 0 + + # Size of the grids + self.sizeX = None + self.sizeY = None + + # GPU that the prednet model will use + self.device = 'cuda:0' + + # Whether the images have been made (for testing) + self.madeExample = True + + # Model directry + # Importing models + modelDir = "/navigator/data/perception/models/prednet.pt" + + # Sets the device to the rigth GPU + # torch.cuda.set_device(torch.device(self.device)) + # torch.cuda.empty_cache() + + # Prints out the GPU being used + self.get_logger().info("Current GPU device: " + str(torch.cuda.current_device())) + + # Checks if Cuda is avaiable + if torch.cuda.is_available(): + self.get_logger().info("CUDA available! Inference on GPU.") + else: + self.get_logger().info("Inference on CPU.") + + # Loads the prednet model + try: + self.prednet_model = torch.jit.load(modelDir, map_location=torch.device(self.device)) + except: + raise Exception("Couldn't load prednet model") + + # Makes sures the model is on the GPU + try: + self.prednet_model.to(torch.device(self.device)) + except: + raise Exception("Couldn't load cuda") + + # Evaluates the model to make sure it's working correctly + try: + self.prednet_model.eval() + except: + raise Exception("Couldn't eval model") + + # Updates the clock for the header + def clock_cb(self, msg): + self.clock = msg.clock + + # Adds masses to history + def masses_callback(self, mass): + if self.clock.sec + 1e-9 * self.clock.nanosec - self.lastAccepted < 1. / self.frameRate - 0.01: + return + + + # self.get_logger().info(str(self.clock.sec + 1e-9 * self.clock.nanosec)) + # Sets the grid size to the given grid size + self.sizeX = mass.width + self.sizeY = mass.height + + # Iterates Time + self.time += 1 + + # If less than 5 previous masses have been read then append to the back of the array + if self.time <= 5: + self.history_m.append(mass) + # Else Shift the array backwards and add the new mass to the 4th index + else: + for i in range(4): + self.history_m[i] = self.history_m[i + 1] + + self.history_m[4] = mass + + # All the requrired data to make a prediction + self.data_acquired = True + + #Updates last accepted time + self.lastAccepted = self.clock.sec + 1e-9 * self.clock.nanosec + + + + def makePrediction(self): + # 0.09s average prediction time + + # If there isn't enough past data to make a prediction + if not self.data_acquired: + return + + # To check how long it takes to make a prediction + startTime = self.get_clock().now() + + # Creates tensor frames onto the GPU + tensorFrames = self.createTensorFromFrames() + + # *** For Testing *** + # Saves the image of the current occupancy grid + if not self.madeExample and self.time > 100: + IMAGES_FN = '/navigator/src/perception/prednet_inference/predictionTest/' + + fig1 = plt.figure() + ax1 = fig1.add_subplot(111) + displayOutput = ( + tensorFrames[0, 4, 0, :, :] * 0.5 + (tensorFrames[0, 4, 1, :, :] * -0.5 + 0.5)) * 100 + displayOutput = displayOutput.cpu().detach().numpy() + h = ax1.matshow(displayOutput) + plt.colorbar(h) + fig1.savefig(IMAGES_FN + 'original_5' + '.png') + plt.close() + + # Makes the prediction and publishes the prediction + prediction = self.Infer(tensorFrames) + self.Publish(prediction) + + # *** For Testing *** + # Saves the images of the predicted occupancy grids + if not self.madeExample and self.time > 100: + self.get_logger().info("Making visualization") + self.madeExample = True + IMAGES_FN = '/navigator/src/perception/prednet_inference/predictionTest/' + + displayOutput = torch.empty(20, self.sizeX, self.sizeY) + for i in range(prediction.shape[1]): + displayOutput[i] = ( + prediction[0, i, 0, :, :] * 0.5 + (prediction[0, i, 1, :, :] * -0.5 + 0.5)) * 100 + # displayOutput = (prediction[0,:,0, :, :] * 0.5 + (prediction[0,:,1, :, :] * -0.5 + 0.5)) * 100 + displayOutput = displayOutput.cpu().detach().numpy() + + for i in range(displayOutput.shape[0]): + fig1 = plt.figure() + ax1 = fig1.add_subplot(111) + h = ax1.matshow(displayOutput[i]) + plt.colorbar(h) + # plt.show()[] + fig1.savefig(IMAGES_FN + 'prediction_example_' + + str(i) + '.png') + plt.close() + + # Gets the total time takes to make the prediction + totalTimeTaken = self.get_clock().now() - startTime + + # self.get_logger().info("Published the model prednet Model Prediction in " + str(totalTimeTaken.nanoseconds / pow(10,9))) + + def createTensorFromFrames(self): + # Creates the tensor object + input_data = torch.empty( + (1, 20, 2, self.sizeX, self.sizeY), device=torch.device(self.device)) + + # Gets the 5 known past masses + for i in range(5): + # Puts the masses into the tensor + input_data[0, i, 0] = torch.tensor( + np.array(self.history_m[i].occ).reshape((self.sizeX, self.sizeY))) + input_data[0, i, 1] = torch.tensor( + np.array(self.history_m[i].free).reshape((self.sizeX, self.sizeY))) + + return input_data + + def Infer(self, input): + # Makes the prediction using the prednet model + output = self.prednet_model(input) + + return output + + def Publish(self, output): + # Prediction message instantiation + self.prediction_msg = Egma() + + # Moves the output off the GPU onto the CPU + new_output = output.to("cpu") + # 5+ indexs are the predicted images + new_output = new_output[:, 5:, :, :, :] + + # Gets the clock for the headers + cur_clock = self.clock + + probability_grids = [] + + for i in range(new_output.shape[1]): + + # Makes a new clock for time that the occupancy grid is predicted for + cur_clock = copy.deepcopy(cur_clock) + cur_clock.nanosec = cur_clock.nanosec + pow(10, 7) + if cur_clock.nanosec >= pow(10, 9): + cur_clock.nanosec = cur_clock.nanosec - pow(10, 9) + cur_clock.sec = cur_clock.sec + 1 + + # Creates the occupancy grid message + occ_grid_msg = OccupancyGrid() + occ_grid_msg.header.stamp = cur_clock + occ_grid_msg.header.frame_id = "base_link" + + occ_grid_msg.info.resolution = 1. / 3. + occ_grid_msg.info.width = self.sizeX + occ_grid_msg.info.height = self.sizeY + + # Calcualtes the probabilitisc occupancy grid + prob_2D = (new_output[0, i, 0] * 0.5 + + (new_output[0, i, 1] * -0.5 + 0.5)) * 100 + probability_grids.append(prob_2D.detach().numpy()) + + # Flattens the grid and puts it into the message + occ_grid_msg.data = prob_2D.flatten().type(torch.int8).numpy().tolist() + + output_occ = new_output + + # Adds the occ grid message to the prediction message + self.prediction_msg.egma.append(occ_grid_msg) + + # aggregate_probability = np.zeros((128, 128)) + # for grid in probability_grids: + # aggregate_probability += grid + + # Only consider the last timeframe + aggregate_probability = probability_grids[-1] + + aggregate_probability /= len(probability_grids) + + aggregate_probability = aggregate_probability.T # Flip rows and columns + # plt.imshow(aggregate_probability) + # plt.show() + + # Publish the prediction message + self.pred_all_pub.publish(self.prediction_msg) + + # Publish combined (flattened) message + combined_grid = OccupancyGrid() + combined_grid.info = self.prediction_msg.egma[0].info + combined_grid.data = Array( + 'b', aggregate_probability.ravel().astype(np.int8)) + combined_grid.header.stamp = self.clock + combined_grid.header.frame_id = "base_link" + combined_grid.info.origin.position.z = 0.2 + combined_grid.info.origin.position.x = -64.0 * (1. / 3.) + combined_grid.info.origin.position.y = -64.0 * (1. / 3.) + self.prednet_combined_pub.publish(combined_grid) + + +def main(args=None): + rclpy.init(args=args) + + prednet_node = PredNetNode() + + rclpy.spin(prednet_node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + prednet_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/perception/prednet_inference/resource/prednet_inference b/src/perception/prednet_inference/resource/prednet_inference new file mode 100755 index 000000000..e69de29bb diff --git a/src/perception/prednet_inference/setup.cfg b/src/perception/prednet_inference/setup.cfg new file mode 100755 index 000000000..6a730c283 --- /dev/null +++ b/src/perception/prednet_inference/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/prednet_inference +[install] +install-scripts=$base/lib/prednet_inference diff --git a/src/perception/prednet_inference/setup.py b/src/perception/prednet_inference/setup.py new file mode 100755 index 000000000..2eb8ad99b --- /dev/null +++ b/src/perception/prednet_inference/setup.py @@ -0,0 +1,29 @@ +from setuptools import setup +from glob import glob +import os + +package_name = 'prednet_inference' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + (os.path.join('share', package_name), glob('launch/*.launch.py')) + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='Nova', + maintainer_email='project.nova@utdallas.edu', + description='TODO: Package description', + license='TODO: License declaration', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'prednet_inference_node = prednet_inference.prednet_inference_node:main', + ], + }, +) diff --git a/src/perception/segmentation/segmentation/image_projection_node.py b/src/perception/segmentation/segmentation/image_projection_node.py new file mode 100755 index 000000000..8fd0d34c7 --- /dev/null +++ b/src/perception/segmentation/segmentation/image_projection_node.py @@ -0,0 +1,334 @@ +''' +Package: segmentation + File: image_projection_node.py + Author: Will Heitman (w at heit dot mn) + +Node to project 2D semantic segmentation results onto a 3D point cloud +''' + + +import rclpy +import ros2_numpy as rnp +import numpy as np +from rclpy.node import Node +from scipy.spatial.transform import Rotation as R +import sys +import time +from tf2_ros import TransformException +from tf2_ros.buffer import Buffer +from tf2_ros.transform_listener import TransformListener + +# Message definitions +from geometry_msgs.msg import TransformStamped +from nav_msgs.msg import OccupancyGrid +from rosgraph_msgs.msg import Clock +from sensor_msgs.msg import CameraInfo, Image, PointCloud2 +from std_msgs.msg import Float32 + +import image_geometry +import matplotlib.pyplot as plt + +import struct + +name_to_dtypes = { + "rgb8": (np.uint8, 3), + "rgba8": (np.uint8, 4), + "rgb16": (np.uint16, 3), + "rgba16": (np.uint16, 4), + "bgr8": (np.uint8, 3), + "bgra8": (np.uint8, 4), + "bgr16": (np.uint16, 3), + "bgra16": (np.uint16, 4), + "mono8": (np.uint8, 1), + "mono16": (np.uint16, 1), + + # for bayer image (based on cv_bridge.cpp) + "bayer_rggb8": (np.uint8, 1), + "bayer_bggr8": (np.uint8, 1), + "bayer_gbrg8": (np.uint8, 1), + "bayer_grbg8": (np.uint8, 1), + "bayer_rggb16": (np.uint16, 1), + "bayer_bggr16": (np.uint16, 1), + "bayer_gbrg16": (np.uint16, 1), + "bayer_grbg16": (np.uint16, 1), + + # OpenCV CvMat types + "8UC1": (np.uint8, 1), + "8UC2": (np.uint8, 2), + "8UC3": (np.uint8, 3), + "8UC4": (np.uint8, 4), + "8SC1": (np.int8, 1), + "8SC2": (np.int8, 2), + "8SC3": (np.int8, 3), + "8SC4": (np.int8, 4), + "16UC1": (np.uint16, 1), + "16UC2": (np.uint16, 2), + "16UC3": (np.uint16, 3), + "16UC4": (np.uint16, 4), + "16SC1": (np.int16, 1), + "16SC2": (np.int16, 2), + "16SC3": (np.int16, 3), + "16SC4": (np.int16, 4), + "32SC1": (np.int32, 1), + "32SC2": (np.int32, 2), + "32SC3": (np.int32, 3), + "32SC4": (np.int32, 4), + "32FC1": (np.float32, 1), + "32FC2": (np.float32, 2), + "32FC3": (np.float32, 3), + "32FC4": (np.float32, 4), + "64FC1": (np.float64, 1), + "64FC2": (np.float64, 2), + "64FC3": (np.float64, 3), + "64FC4": (np.float64, 4) +} + +img_shape = (512, 1024) + + +class ImageProjectioNode(Node): + + def __init__(self): + super().__init__('image_projection_node') + self.get_logger().info("Ready to project!") + + lidar_sub = self.create_subscription( + PointCloud2, "/lidar/fused", self.lidarCb, 1) + + self.semantic_lidar_pub = self.create_publisher( + PointCloud2, "/lidar/semantic", 10) + + left_camera_info_sub = self.create_subscription( + CameraInfo, '/carla/hero/rgb_left/camera_info', self.leftCameraInfoCb, 1) + + left_camera_image_sub = self.create_subscription( + Image, '/semantic/left', self.leftCameraImageCb, 1) + + right_camera_image_sub = self.create_subscription( + Image, '/semantic/right', self.rightCameraImageCb, 1) + + right_camera_info_sub = self.create_subscription( + CameraInfo, '/carla/hero/rgb_right/camera_info', self.rightCameraInfoCb, 1) + + self.tf_buffer = Buffer() + self.tf_listener = TransformListener(self.tf_buffer, self) + + self.left_camera_frame = 'hero/rgb_left' + self.right_camera_frame = 'hero/rgb_right' + self.left_cam_model: image_geometry.PinholeCameraModel = None + self.right_cam_model: image_geometry.PinholeCameraModel = None + + self.left_semantic_image = None + self.right_semantic_image = None + + def imageToNumpy(self, msg: Image) -> np.array: + """Converts Image message to numpy array + + Args: + msg (Image) + + Raises: + TypeError if image encoding not recognized + + Returns: + np.array + """ + if not msg.encoding in name_to_dtypes: + raise TypeError('Unrecognized encoding {}'.format(msg.encoding)) + + dtype_class, channels = name_to_dtypes[msg.encoding] + dtype = np.dtype(dtype_class) + dtype = dtype.newbyteorder('>' if msg.is_bigendian else '<') + shape = (msg.height, msg.width, channels) + + data = np.frombuffer(msg.data, dtype=dtype).reshape(shape) + data.strides = ( + msg.step, + dtype.itemsize * channels, + dtype.itemsize + ) + + if channels == 1: + data = data[..., 0] + return data + + def leftCameraInfoCb(self, msg: CameraInfo) -> None: + """Sets camera info for left camera + + Args: + msg (CameraInfo) + + Returns: + None + """ + if self.left_cam_model is not None: + return # Already set, skip + self.left_cam_model = image_geometry.PinholeCameraModel() + self.left_cam_model.fromCameraInfo(msg) + + def rightCameraInfoCb(self, msg: CameraInfo): + """Sets camera info for right camera + + Args: + msg (CameraInfo) + + Returns: + None + """ + if self.right_cam_model is not None: + return # Already set, skip + self.right_cam_model = image_geometry.PinholeCameraModel() + self.right_cam_model.fromCameraInfo(msg) + + def leftCameraImageCb(self, msg: Image): + self.left_semantic_image = self.imageToNumpy(msg) + + def rightCameraImageCb(self, msg: Image): + self.right_semantic_image = self.imageToNumpy(msg) + + def tagPoints(self, camera_frame: str, pts: np.array, semantic_img: np.array) -> np.array: + """Given LiDAR point cloud and semantic segmentation image, paint the image + onto the point cloud, assigning a class to each point. + + Args: + frame (str) + pts (np.array): LiDAR points, where each row is a point [x,y,z] + semantic_img (np.array): n x m semantic segmentation image + + Returns: + np.array: Classified LiDAR points, where each row is a point [x,y,z,class] + """ + t = TransformStamped() + + try: + t = self.tf_buffer.lookup_transform( + camera_frame, 'base_link', rclpy.time.Time()) + except TransformException as ex: + self.get_logger().info( + f'Could not transform to camera frame: {ex}') + return + + # Rotate to camera frame + q = t.transform.rotation + tf_rotation: R = R.from_quat([q.x, q.y, q.z, q.w]) + lidar_array_tfed = tf_rotation.apply(pts) + + # Translate to camera frame + lidar_array_tfed += [t.transform.translation.x, + t.transform.translation.y, + t.transform.translation.z] + + classified_pts = [] + rgb = [] + + for idx, pt in enumerate(lidar_array_tfed): + uv = self.right_cam_model.project3dToPixel(pt) + pixel_coords = np.array(uv).astype(int) + + if pixel_coords[0] > 1023 or pixel_coords[0] < 0: + continue + elif pixel_coords[1] > 511 or pixel_coords[1] < 0: + continue + + pixel_class = semantic_img[pixel_coords[1], pixel_coords[0]] + # print(pixel_class) + r = int(pixel_class[0]) + g = int(pixel_class[1]) + b = int(pixel_class[2]) + a = 255 + rgb.append(struct.unpack('I', struct.pack('BBBB', b, g, r, a))[0]) + # classified_pt = np.append(pts[idx], pixel_class) + classified_pts.append(pts[idx]) + + classified_pts = np.array(classified_pts) # Convert to np array + rgb = np.array(rgb).astype(np.uint32) + + if len(classified_pts) < 1: + return + + xyzc = np.zeros(classified_pts.shape[0], dtype=[ + ('x', np.float32), + ('y', np.float32), + ('z', np.float32), + ('rgb', np.uint32) + ]) + + xyzc['x'] = classified_pts[:, 0] + xyzc['y'] = classified_pts[:, 1] + xyzc['z'] = classified_pts[:, 2] + xyzc['rgb'] = rgb + + # self.get_logger().info(str(xyzc[rgb == 4286595200])) + + return xyzc + + def lidarCb(self, msg: PointCloud2): + """When LiDAR data is received, trim it, call tagPoints for each camera, and publish the result. + + Args: + msg (PointCloud2): _description_ + + Returns: + _type_: _description_ + """ + if self.left_cam_model is None or self.right_cam_model is None: + return # Camera models not yet available. + + if self.left_semantic_image is None or self.right_semantic_image is None: + return # Semantic results not yet available. + + # Convert point cloud message to numpy array + lidar_array = rnp.numpify(msg) + + # Strip away the dtypes + lidar_array_raw = np.vstack( + (lidar_array['x'], lidar_array['y'], lidar_array['z'])).T + + # Downsampe to 25% + lidar_array_raw = lidar_array_raw[::4] + + # Trim distance + MAX_DISTANCE = 40.0 # meters + dist = np.linalg.norm(lidar_array_raw, axis=1) + lidar_array_raw = lidar_array_raw[dist < MAX_DISTANCE] + # Only points in front of us + lidar_array_raw = lidar_array_raw[lidar_array_raw[:, 0] > 0.0] + + start = time.time() + + left_classified_pts = self.tagPoints(self.left_camera_frame, lidar_array_raw, + self.left_semantic_image) + + left_classified_pts = left_classified_pts[left_classified_pts['y'] > 0] + + right_classified_pts = self.tagPoints(self.right_camera_frame, lidar_array_raw, + self.right_semantic_image) + + right_classified_pts = right_classified_pts[right_classified_pts['y'] < 0] + + classified_pts = np.concatenate( + (left_classified_pts, right_classified_pts), axis=0) + + # Convert our combined classified points back to a PointCloud2 message + result_msg: PointCloud2 = rnp.msgify(PointCloud2, classified_pts) + result_msg.header = msg.header + + self.semantic_lidar_pub.publish(result_msg) + + +def main(args=None): + rclpy.init(args=args) + + lidar_projection_node = ImageProjectioNode() + + rclpy.spin(lidar_projection_node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + lidar_projection_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/perception/segmentation/segmentation/image_segmentation_node.py b/src/perception/segmentation/segmentation/image_segmentation_node.py old mode 100755 new mode 100644 index e8ff5a73b..f2018e43e --- a/src/perception/segmentation/segmentation/image_segmentation_node.py +++ b/src/perception/segmentation/segmentation/image_segmentation_node.py @@ -8,6 +8,7 @@ import rclpy +from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy, Duration, QoSDurabilityPolicy # import ros2_numpy as rnp import numpy as np from rclpy.node import Node @@ -26,6 +27,9 @@ import matplotlib.pyplot as plt +import cv2 +from cv_bridge import CvBridge + # OpenMMSegmentation from mmseg.apis import inference_segmentor, init_segmentor import mmcv @@ -83,6 +87,7 @@ "64FC4": (np.float64, 4) } + class ImageSegmentationNode(Node): def __init__(self): @@ -90,19 +95,51 @@ def __init__(self): config_file = '/mmsegmentation/configs/pspnet/pspnet_r18-d8_512x1024_80k_cityscapes.py' checkpoint_file = '/navigator/data/perception/pspnet_r18-d8_512x1024_80k_cityscapes_20201225_021458-09ffa746.pth' - self.model = init_segmentor(config_file, checkpoint_file, device='cuda:0') + self.model = init_segmentor( + config_file, checkpoint_file, device='cuda:0') # Change this to '1,' 2,' etc to change GPU used + + image_qos_policy = QoSProfile( + history=QoSHistoryPolicy.KEEP_LAST, + reliability=QoSReliabilityPolicy.BEST_EFFORT, + depth=1, + durability=QoSDurabilityPolicy.VOLATILE, + lifespan=Duration(seconds=0, nanoseconds=2e8) + ) - self.left_rgb_sub = self.create_subscription(Image, "/carla/hero/rgb_left/image", self.rgb_left_cb, 10) - self.left_result_pub = self.create_publisher(Image, '/semantic/left_mono', 10) + self.left_rgb_sub = self.create_subscription( + Image, "/carla/hero/rgb_left/image", self.rgbLeftCb, image_qos_policy) - self.right_rgb_sub = self.create_subscription(Image, "/carla/hero/rgb_right/image", self.rgb_right_cb, 10) - self.right_result_pub = self.create_publisher(Image, '/semantic/right_mono', 10) + self.left_result_pub = self.create_publisher( + Image, '/semantic/left', 1) + self.right_rgb_sub = self.create_subscription( + Image, "/carla/hero/rgb_right/image", self.rgbRightCb, image_qos_policy) + self.right_result_pub = self.create_publisher( + Image, '/semantic/right', 1) self.idx = 0 + + self.clock_sub = self.create_subscription( + Clock, '/clock', self.clock_cb, 1) + self.clock = Clock() # model.show_result(img, result, out_file='result.jpg', opacity=1.0) + self.bridge = CvBridge() + + def clock_cb(self, msg: Clock): + self.clock = msg + + def imageToNumpy(self, msg) -> np.ndarray: + """Converts Image message to numpy array + + Args: + msg (Image): ROS Image message - def image_to_numpy(self, msg): + Raises: + TypeError: If image encoding is not recognized + + Returns: + np.ndarray: Image as np array + """ if not msg.encoding in name_to_dtypes: raise TypeError('Unrecognized encoding {}'.format(msg.encoding)) @@ -119,10 +156,25 @@ def image_to_numpy(self, msg): ) if channels == 1: - data = data[...,0] + data = data[..., 0] return data - def numpy_to_image(self, arr, encoding): + def numpyToImage(self, arr: np.ndarray, encoding: str) -> Image: + """Converts np array to Image message + + Args: + arr (np.ndarray): _description_ + encoding (str): _description_ + + Raises: + TypeError: Unrecognized image encoding requested + TypeError: Input array shape is invalid + TypeError: Image channels did not match requested encoding + TypeError: Array dtype was invalid + + Returns: + Image: ROS Image message + """ if not encoding in name_to_dtypes: raise TypeError('Unrecognized encoding {}'.format(encoding)) @@ -149,9 +201,9 @@ def numpy_to_image(self, arr, encoding): )) # make the array contiguous in memory, as mostly required by the format - contig = np.ascontiguousarray(arr) - im.data = contig.tostring() - im.step = contig.strides[0] + # contig = np.ascontiguousarray(arr) + im.data = arr.tostring() + im.step = arr.strides[0] im.is_bigendian = ( arr.dtype.byteorder == '>' or arr.dtype.byteorder == '=' and sys.byteorder == 'big' @@ -159,29 +211,65 @@ def numpy_to_image(self, arr, encoding): return im - def rgb_left_cb(self, msg: Image): - img_array = mmcv.imread("/navigator/demo.png") - - img_array = self.image_to_numpy(msg)[:,:,:3] # Cut out alpha + def convertToColor(self, mono_result: np.ndarray) -> np.array: + """Converts a one-channel segmentation result to a colored image using the CityScapes coloring scheme. + + Args: + mono_result (np.array): Segmentation result (2d) + + Returns: + np.array: Colored result (3D array, accounting for RGB channel) + """ + result_rgb = np.zeros( + (mono_result.shape[0], mono_result.shape[1], 3), dtype=np.uint8) + result_rgb[:, :][mono_result == 0] = [128, 64, 128] # Road + result_rgb[:, :][mono_result == 1] = [244, 35, 232] # Sidewalk + result_rgb[:, :][np.logical_or(np.logical_or( + mono_result == 2, mono_result == 3), mono_result == 4)] = [70, 70, 70] # Building, wall, fence + result_rgb[:, :][mono_result == 3] = [100, 40, 40] # Fence + result_rgb[:, :][mono_result == 5] = [153, 153, 153] # Pole + result_rgb[:, :][mono_result == 6] = [250, 170, 30] # Traffic light + result_rgb[:, :][mono_result == 7] = [220, 220, 0] # Traffic light + result_rgb[:, :][mono_result == 8] = [107, 142, 35] # Vegetation + result_rgb[:, :][mono_result == 9] = [145, 170, 100] # Terrain + result_rgb[:, :][mono_result == 10] = [70, 130, 180] # Sky + result_rgb[:, :][mono_result == 11] = [220, 20, 60] # Person + result_rgb[:, :][np.logical_or(np.logical_or( + np.logical_or(mono_result == 12, mono_result == 13), + np.logical_or(mono_result == 14, mono_result == 15)), + mono_result == 16)] = [0, 0, 142] # Car, rider, truck, bus, train, motorcycle + result_rgb[:, :][np.logical_or(mono_result == 17, mono_result == 18)] = [ + 119, 11, 32] # Building, wall, fence + return result_rgb + + def rgbLeftCb(self, msg: Image): + img_array = self.bridge.imgmsg_to_cv2( + msg, 'rgb8')[:, :, :3] # Cut out alpha + + # Actually performs the inference result = inference_segmentor(self.model, img_array)[0] - result *= 40 - result_msg = self.numpy_to_image(result.astype(np.uint8), 'mono8') - result_msg.header = msg.header + result_rgb = self.convertToColor(result) + + result_msg_rgb = self.bridge.cv2_to_imgmsg(result_rgb, encoding='rgb8') + result_msg_rgb.header = msg.header - self.left_result_pub.publish(result_msg) + self.left_result_pub.publish(result_msg_rgb) - def rgb_right_cb(self, msg: Image): - img_array = mmcv.imread("/navigator/demo.png") + def rgbRightCb(self, msg: Image): + img_array = self.bridge.imgmsg_to_cv2( + msg, 'rgb8')[:, :, :3] # Cut out alpha - img_array = self.image_to_numpy(msg)[:,:,:3] # Cut out alpha + # Actually performs the inference result = inference_segmentor(self.model, img_array)[0] - result *= 40 - result_msg = self.numpy_to_image(result.astype(np.uint8), 'mono8') - result_msg.header = msg.header + result_rgb = self.convertToColor(result) + + result_msg_rgb = self.bridge.cv2_to_imgmsg(result_rgb, encoding='rgb8') + result_msg_rgb.header = msg.header + + self.right_result_pub.publish(result_msg_rgb) - self.right_result_pub.publish(result_msg) def main(args=None): rclpy.init(args=args) diff --git a/src/perception/segmentation/setup.py b/src/perception/segmentation/setup.py index 60f7ed71e..94e75bf58 100755 --- a/src/perception/segmentation/setup.py +++ b/src/perception/segmentation/setup.py @@ -24,6 +24,7 @@ entry_points={ 'console_scripts': [ 'image_segmentation_node = segmentation.image_segmentation_node:main', + 'image_projection_node = segmentation.image_projection_node:main', ], }, ) diff --git a/src/perception/state_estimation/setup.py b/src/perception/state_estimation/setup.py index 9d03f762a..d93e2dfad 100755 --- a/src/perception/state_estimation/setup.py +++ b/src/perception/state_estimation/setup.py @@ -25,6 +25,7 @@ entry_points={ 'console_scripts': [ 'gnss_processing_node = state_estimation.gnss_processing_node:main', + 'gnss_averaging_node = state_estimation.gnss_averaging_node:main', 'mcl_node = state_estimation.mcl_node:main', ], } diff --git a/src/perception/state_estimation/state_estimation/gnss_averaging_node.py b/src/perception/state_estimation/state_estimation/gnss_averaging_node.py new file mode 100755 index 000000000..bfa2a19de --- /dev/null +++ b/src/perception/state_estimation/state_estimation/gnss_averaging_node.py @@ -0,0 +1,287 @@ +''' +Package: state_estimation + File: gnss_averaging_node.py + Author: Will Heitman (w at heit dot mn) + +Simple state machine that combined GNSS averaging with dead reckoning for CARLA. + +Uses a two-state machine: + +1. Stationary state: Node collects GNSS estimates into an array while speed <0.1 m/s +2. Moving state: Node dead reckons to update current_pose. + +On 1->2 transition: GNSS estimates in array are average to form updated current_pose, + only if car was in (1) for >5 seconds. + +Subscribes to: +- Raw GNSS (Odometry) +- Speedometer + +Publishes: +- Corrected pose (Odometry) +- Diagnostic status +''' + +import math +import rclpy +import ros2_numpy as rnp +import numpy as np +import matplotlib.pyplot as plt +from rclpy.node import Node +from builtin_interfaces.msg import Time +from tf2_ros import TransformBroadcaster + +# Message definitions +from carla_msgs.msg import CarlaSpeedometer +from diagnostic_msgs.msg import DiagnosticStatus +from geometry_msgs.msg import PoseStamped, TransformStamped, Vector3 +from nav_msgs.msg import Odometry +from rosgraph_msgs.msg import Clock +from sensor_msgs.msg import Imu + + +class GnssAveragingNode(Node): + + def __init__(self): + super().__init__('gnss_averaging_node') + + self.clock_sub = self.create_subscription( + Clock, '/clock', self.clock_cb, 1) + + self.imu_sub = self.create_subscription( + Imu, '/carla/hero/imu', self.imu_cb, 1) + + self.speedometer_sub = self.create_subscription( + CarlaSpeedometer, '/carla/hero/speedometer', self.speedometer_cb, 1) + + self.raw_gnss_sub = self.create_subscription( + Odometry, '/odometry/gnss_raw', self.raw_gnss_cb, 10 + ) + + self.true_pose_sub = self.create_subscription( + PoseStamped, '/true_pose', self.true_pose_cb, 1) + + self.smoothed_gnss_sub = self.create_subscription( + Odometry, '/odometry/gnss_processed', self.smoothed_gnss_cb, 10 + ) + + self.result_pub = self.create_publisher( + Odometry, '/odometry/processed', 1) + + self.diagnostic_pub = self.create_publisher( + DiagnosticStatus, '/node_statuses', 1) + + self.tf_broadcaster = TransformBroadcaster(self) + + self.diagnostic_pub_timer = self.create_timer( + 0.25, self.publish_diagnostics) + + self.speed = 0.0 # rad/s + self.clock: Time = None + self.last_update_time = None + self.heading_rate = 0.0 # rad/s + self.is_stationary = True + self.cached_gnss_poses = [] + self.current_pose = None # [x, y, heading] + self.yaw = 0.0 + + # This variable describes whether or not our pose was recently refreshed by average GNSS + # If the car has not recently been stationary for a significant period of time, + # this will be false, and our result will likely be inaccurate. + self.averaging_is_fresh = False + self.last_refresh_time = -1.0 + + # Diagnostic state + self.diag_state = 'OK' + + def smoothed_gnss_cb(self, msg: Odometry): + q = msg.pose.pose.orientation + + if q.z < 0: + self.yaw = abs(2*np.arccos(q.w) - 2 * np.pi) + else: + self.yaw = 2 * np.arccos(q.w) + + if self.yaw > np.pi: + self.yaw -= 2 * np.pi + + def true_pose_cb(self, msg: PoseStamped): + if self.current_pose is None: + return + dx = abs(msg.pose.position.x - self.current_pose[0]) + dy = abs(msg.pose.position.y*-1 - self.current_pose[1]) + error = math.sqrt(dx**2 + dy**2) + print(f"Error: {error}") + + def publish_diagnostics(self): + status = DiagnosticStatus() + status.name = 'localization' + status.level = DiagnosticStatus.OK + + if self.clock is None: + status.level = DiagnosticStatus.ERROR + status.message = "Clock not yet received." + self.diagnostic_pub.publish(status) + return + + current_time = self.clock.sec + self.clock.nanosec*1e-9 + dt = current_time - self.last_update_time + if dt > 0.3: # seconds + status.level = DiagnosticStatus.ERROR + status.message = f"Localization last updated {dt} seconds ago." + + last_refresh_gap = current_time - self.last_refresh_time + if last_refresh_gap > 15.0 and not self.is_stationary: + # It's been 15 seconds since our car was last stationary + # and our pose was reset from averaged GNSS data + status.level = DiagnosticStatus.WARN + status.message = f"Localization last refreshed {last_refresh_gap} seconds ago. Result likely inaccurate." + + elif last_refresh_gap > 30.0 and not self.is_stationary: + # It's been 30 seconds since our car was last stationary + # and our pose was reset from averaged GNSS data. We need to stop to refresh. + status.level = DiagnosticStatus.ERROR + status.message = f"Localization last refreshed {last_refresh_gap} seconds ago. Result likely highly inaccurate." + + else: + status.level = DiagnosticStatus.OK + status.message = "Localization operating normally." + + self.diagnostic_pub.publish(status) + + def raw_gnss_cb(self, msg: Odometry): + if self.clock is None: + self.get_logger().debug('Clock not yet received. Skipping update.') + return + + if self.current_pose is None: + self.current_pose = np.array([ + msg.pose.pose.position.x, + msg.pose.pose.position.y, + 2*math.asin(msg.pose.pose.orientation.z) + ]) + self.get_logger().info("Initializing to first GNSS pose") + + current_time = self.clock.sec + self.clock.nanosec*1e-9 + + if self.speed < 0.1: + self.is_stationary = True + + gnss_pose_arr = np.array([ + msg.pose.pose.position.x, + msg.pose.pose.position.y, + self.yaw + ]) + + if gnss_pose_arr[2] > math.pi: + gnss_pose_arr[2] -= 2*math.pi + + self.cached_gnss_poses.append(gnss_pose_arr) + + if len(self.cached_gnss_poses) % 10 == 0: + print(f"Cache now has {len(self.cached_gnss_poses)} poses") + + if len(self.cached_gnss_poses) > 10: + cached_poses = np.array(self.cached_gnss_poses) + self.current_pose = np.mean(cached_poses, axis=0) + + # if len(self.cached_gnss_poses) > 50: + # self.cached_gnss_poses = self.cached_gnss_poses[:-50] + + elif self.is_stationary: + # We're over the stationary speed, so update our state + self.is_stationary = False + + # Calculate average pose + cached_poses = np.array(self.cached_gnss_poses) + average_pose = np.mean(cached_poses, axis=0) + + if len(cached_poses) < 2: + return + + average_pose[2] %= 2*math.pi # Wrap to [0, 2*pi] + + self.get_logger().info( + f"Pose was corrected by {average_pose-self.current_pose}") + # plt.scatter(cached_poses[:, 0], cached_poses[:, 1], c='blue') + # plt.scatter(average_pose[0], average_pose[1], c='green') + # plt.show() + + self.current_pose = average_pose + + self.last_refresh_time = current_time + + self.cached_gnss_poses.clear() + + else: + # Dead reckon + dt = current_time - self.last_update_time + # print("Dead reckoning with dt = {:.2f}".format(dt)) + + # Update heading by integrating heading rate + self.current_pose[2] += self.heading_rate * dt * 1.2 + self.current_pose[2] %= 2 * np.pi + # self.current_pose[2] = 2*math.asin(msg.pose.pose.orientation.z) + + # move in the (noisy) commanded direction + dist = (self.speed * dt) + self.current_pose[0] += np.cos(self.current_pose[2]) * dist + self.current_pose[1] += np.sin(self.current_pose[2]) * dist + + # Get current time in seconds + self.last_update_time = current_time + + result_msg = Odometry() + result_msg.header = msg.header + result_msg.child_frame_id = 'hero' + result_msg.pose.pose.position.x = self.current_pose[0] + result_msg.pose.pose.position.y = self.current_pose[1] + result_msg.pose.pose.position.z = 0.0 # TODO: Don't assume z=0 + result_msg.pose.pose.orientation.w = math.cos(self.current_pose[2]/2) + result_msg.pose.pose.orientation.z = math.sin(self.current_pose[2]/2) + result_msg.twist.twist.linear.x = self.speed + result_msg.twist.twist.angular.z = self.heading_rate + + self.result_pub.publish(result_msg) + + # Publish our map->base_link tf + t = TransformStamped() + t.header = msg.header + t.child_frame_id = 'hero' + transl = Vector3() + transl.x = self.current_pose[0] + transl.y = self.current_pose[1] + transl.z = 0.0 # TODO: Stop assuming flat surface + t.transform.translation = transl + t.transform.rotation = result_msg.pose.pose.orientation + # self.tf_broadcaster.sendTransform(t) + + def clock_cb(self, msg: Clock): + if self.last_update_time is None: + self.last_update_time = msg.clock.sec + msg.clock.nanosec*1e-9 + + self.clock = msg.clock + + def imu_cb(self, msg: Imu): + self.heading_rate = msg.angular_velocity.z + + def speedometer_cb(self, msg: CarlaSpeedometer): + self.speed = msg.speed + + +def main(args=None): + rclpy.init(args=args) + + gnss_averaging_node = GnssAveragingNode() + + rclpy.spin(gnss_averaging_node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + gnss_averaging_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/perception/state_estimation/state_estimation/gnss_processing_node.py b/src/perception/state_estimation/state_estimation/gnss_processing_node.py index b6ce03691..f983b8798 100755 --- a/src/perception/state_estimation/state_estimation/gnss_processing_node.py +++ b/src/perception/state_estimation/state_estimation/gnss_processing_node.py @@ -1,6 +1,6 @@ ''' Package: map_management - File: gnss_estimation_node.py + File: gnss_processing_node.py Author: Will Heitman (w at heit dot mn) Very simple node to convert raw GNSS odometry into a map->base_link transform. @@ -20,32 +20,52 @@ from rosgraph_msgs.msg import Clock from sensor_msgs.msg import Imu, NavSatFix -import pymap3d as pm from tf2_ros import TransformBroadcaster from xml.etree import ElementTree as ET +from scipy.spatial.transform import Rotation as R + + +def toRadians(degrees: float): + return degrees * math.pi / 180.0 + + +def latToScale(lat: float) -> float: + """Return UTM projection scale + + Args: + lat (float): degrees latitude + + Returns: + float: projection scale + """ + return math.cos(toRadians(lat)) + + +EARTH_RADIUS_EQUA = 6378137.0 + class GnssProcessingNode(Node): def __init__(self): - super().__init__('gnss_estimation_node') + super().__init__('gnss_processing_node') self.odom_sub = self.create_subscription( Odometry, '/odometry/gnss_raw', self.raw_odom_cb, 10 ) self.gnss_sub = self.create_subscription( - NavSatFix, '/carla/hero/gnss', self.gnss_cb, 10 + NavSatFix, '/carla/hero/gnss', self.gnssCb, 10 ) self.clock_sub = self.create_subscription( - Clock, '/clock', self.clock_cb, 10) + Clock, '/clock', self.clockCb, 10) self.imu_sub = self.create_subscription( - Imu, '/carla/hero/imu', self.imu_cb, 10 + Imu, '/carla/hero/imu', self.imuCb, 10 ) self.world_info_sub = self.create_subscription( - CarlaWorldInfo, '/carla/world_info', self.world_info_cb, 10 + CarlaWorldInfo, '/carla/world_info', self.worldInfoCb, 10 ) self.odom_pub = self.create_publisher( @@ -57,10 +77,10 @@ def __init__(self): ) self.status_pub = self.create_publisher( - DiagnosticStatus, '/status', 1 + DiagnosticStatus, '/node_statuses', 1 ) - self.status_timer = self.create_timer(1.0, self.update_status) + self.status_timer = self.create_timer(1.0, self.updateStatus) self.tf_broadcaster = TransformBroadcaster(self) @@ -94,7 +114,7 @@ def _parse_header_(self, root: ET.Element) -> dict: return (lat0, lon0) - def world_info_cb(self, msg: CarlaWorldInfo): + def worldInfoCb(self, msg: CarlaWorldInfo): if self.lat0 is not None: return if msg.opendrive == "": @@ -103,17 +123,40 @@ def world_info_cb(self, msg: CarlaWorldInfo): self.lat0, self.lon0 = self._parse_header_(root) self.get_logger().info("World info received.") - def gnss_cb(self, msg: NavSatFix): + def latlonToMercator(self, lat: float, lon: float, scale: float) -> tuple: + """Convert geodetic coords (in degrees) to UTM coords (meters) + + Copied to match CARLA: + [LatLonToMercator](https://github.com/carla-simulator/carla/blob/fe3cb6863a604f5c0cf8b692fe2b6300b45b5999/LibCarla/source/carla/geom/GeoLocation.cpp#L38) + + Args: + lat (float): degrees + lon (float): degrees + scale (float): projection scale (see latToScale) + + Returns: + tuple: (x,y) in UTM meters + """ + x = scale * toRadians(lon) * EARTH_RADIUS_EQUA + y = scale * EARTH_RADIUS_EQUA * \ + math.log(math.tan((90.0+lat) * math.pi/360.0)) + + return (x, y) + + def gnssCb(self, msg: NavSatFix): if self.lat0 is None: return - enu_xyz = pm.geodetic2enu( - msg.latitude, - msg.longitude, - msg.altitude, - self.lat0, - self.lon0, - 0.0 - ) + + x0, y0 = self.latlonToMercator( + self.lat0, self.lon0, latToScale(self.lat0)) + + # TODO: Should scale here be from self.lat0? + x, y = self.latlonToMercator( + msg.latitude, msg.longitude, latToScale(msg.latitude)) + + position_x = x - x0 + position_y = y - y0 + odom_msg = Odometry() # The odometry is for the current time-- right now @@ -125,20 +168,20 @@ def gnss_cb(self, msg: NavSatFix): odom_msg.child_frame_id = 'base_link' pos = Point() - pos.x = enu_xyz[0] - pos.y = enu_xyz[1] - pos.z = enu_xyz[2] + pos.x = position_x + pos.y = position_y + pos.z = msg.altitude # TODO: Make relative to georeference odom_msg.pose.pose.position = pos self.raw_odom_pub.publish(odom_msg) - def imu_cb(self, msg: Imu): + def imuCb(self, msg: Imu): self.cached_imu = msg msg.header.stamp - def clock_cb(self, msg: Clock): + def clockCb(self, msg: Clock): self.clock = msg - def update_status(self): + def updateStatus(self): status = DiagnosticStatus() status.name = self.get_name() # Get the node name @@ -183,10 +226,13 @@ def _update_odom_weighted_moving_average_(self, current_pos: Point): wma_pose.position.z = wma_z # IMU orientation is buggy. See imu_cb note. - buggy_quat = self.cached_imu.orientation - heading_x = buggy_quat.x * -0.48 - heading_y = buggy_quat.y * 0.48 - wma_yaw = math.atan2(heading_y, heading_x) + q = self.cached_imu.orientation + heading_x = q.x * -0.48 + heading_y = q.y * 0.48 + wma_yaw = q + + rpy = R.from_quat([q.x, q.y, q.z, q.w]).as_euler('xyz') + wma_yaw = rpy[1] * -np.pi/2 + np.pi # q = cos(theta/2) + sin(theta/2)(xi + yj + zk) # Set x, y = 0 s.t. theta = yaw @@ -255,8 +301,7 @@ def raw_odom_cb(self, msg: Odometry): t.transform.rotation = self.wma_pose.orientation # Uncomment to enable direct map->base_link tf - - self.tf_broadcaster.sendTransform(t) + # self.tf_broadcaster.sendTransform(t) def main(args=None): diff --git a/src/perception/state_estimation/state_estimation/mcl.py b/src/perception/state_estimation/state_estimation/mcl.py old mode 100755 new mode 100644 index d7f2806db..a3e15915f --- a/src/perception/state_estimation/state_estimation/mcl.py +++ b/src/perception/state_estimation/state_estimation/mcl.py @@ -18,7 +18,7 @@ A particle is an np.array: [x, y, heading, weight] ACKNOWLEDGEMENT: -This code is adapted from Roger Labbe's work: +This code is adapted from Roger Labbe's work: https://github.com/rlabbe/Kalman-and-Bayesian-Filters-in-Python/blob/master/12-Particle-Filters.ipynb For a detailed explanation of how the filter works, visit the above link. @@ -34,6 +34,16 @@ import time import matplotlib.pyplot as plt +ROAD_ID = 4286595200 +TRAFFIC_LIGHT_ID = 4294617630 +POLE_ID = 4288256409 + +GRID_ORIGIN_METERS = [-20., -30.] +GRID_ORIGIN_METERS = np.array(GRID_ORIGIN_METERS) +CELL_SIZE = 0.4 # meters/cell + +DO_PLOT_ALIGNMENT = False + class MCL: @@ -56,105 +66,174 @@ def create_gaussian_particles(self, mean: np.array, std: tuple, N: int) -> np.ar return particles - def predict(self, particles: np.array, delta: np.array, std: np.array) -> None: - """Move each particle based on a noisy motion prediction - - Args: - particles (np.array): array of particles - delta (np.array): [dx, dy, dtheta] - std (np.array): standard deviation of delta - """ + def predictMotion(self, particles, u, std, dt, new_heading=None): + """ move according to control input u (heading rate, speed) + with noise Q (std heading change, std velocity)`""" N = len(particles) - # print(particles) - # print(delta) - particles[:] += delta # + (randn(N) * std) - particles += (randn(N, 3) * std) + # update heading - # Wrap heading to [0, 2*pi] - particles[:, 2] %= 2 * np.pi + if new_heading is None: + particles[:, 2] += u[0] * dt + (randn(N) * std[0]) + particles[:, 2] %= 2 * np.pi + else: + particles[:, 2] = new_heading + + # move in the (noisy) commanded direction + dist = (self.previous_speed * dt) + (randn(N) * std[1]) + particles[:, 0] += np.cos(particles[:, 2]) * dist + particles[:, 1] += np.sin(particles[:, 2]) * dist - def update_orig(self, particles: np.array, weights: np.array, z: np.array, R: np.array, landmarks: np.array) -> None: + self.previous_speed = u[1] + + def updateOriginal(self, particles: np.array, weights: np.array, z: np.array, R: np.array, landmarks: np.array) -> None: """Update the weights of each particle based on our current observation using Sequential Importance Sampling (SIS) Args: particles (np.array): particles to update weights (np.array): weights of our particles - z (np.array): _description_ + z (np.array): Distances to nearby landmarks R (np.array): sensor error standard deviation landmarks (np.array): landmark positions [x,y] """ - for i, landmark in enumerate(landmarks): - distance = np.linalg.norm(particles[:, 0:2] - landmark, axis=1) - weights *= scipy.stats.norm(distance, R).pdf(z[i]) + + if len(landmarks) < 1: + return + if len(z) < 1: + return + + # Consider only the nearest landmark + landmark = landmarks[np.argmin( + np.linalg.norm(landmarks-self.mu[:2], axis=1))] + print(f"Nearest lm: {landmark}") + + particle_distances = np.linalg.norm(particles[:, :2]-landmark, axis=1) + print(f"Particle dists: {particle_distances}") + print(f"Observed dists: {z}") + + # pdf() gives the likelihood that the observed distance z + # matches the particle's distance. Higher likelihoods + # mean relatively higher weights. + weights *= scipy.stats.norm(particle_distances, R).pdf(z[0]) + + plt.scatter(particles[:, 0], particles[:, 1], c=weights) + plt.show() weights += 1.e-300 # avoid round-off to zero weights /= sum(weights) # normalize - def update_weights(self, particles, weights, cloud: np.array, cells: np.array, gnss_pose): - """Update weights by checking each particle's alignment in the occupancy grid. + def updateWeights(self, particles, weights, cloud: np.array, grid: np.array, gnss_pose): + """Update the weights of each particle based on our current observation + using Sequential Importance Sampling (SIS) Args: - particles (_type_): _description_ - weights (_type_): _description_ - cloud (np.array): [[x,y], [x,y], ...] - cells (np.array): n rows (x) from map_origin to origin+height_meters, m columns (y) - from map_origin to origin+width_meters. + particles (np.array): particles to update + weights (np.array): weights of our particles + z (np.array): _description_ + R (np.array): sensor error standard deviation + landmarks (np.array): landmark positions [x,y] """ - # The cloud is given in the vehicle frame. - # We need it in the map frame - alignments = [] - # for idx, cell in np.ndenumerate(cells[::10, ::10]): - # if cell == 100: - # plt.scatter(idx[1]*10, idx[0]*10, c='k') + # Crop cloud to nearby + nearby_cloud = cloud[np.linalg.norm(cloud[:, 0:2], axis=1) < 14] - for particle in particles: + # Transform cloud to grid + # 1. Translate to grid origin + cloud_on_grid = np.copy(nearby_cloud) - # First rotate - theta = particle[2] - r = np.array([[np.cos(theta), -1*np.sin(theta)], - [np.sin(theta), np.cos(theta)]]) + cloud_on_grid[:, 0:2] -= GRID_ORIGIN_METERS + # 2. Scale to cell size + cloud_on_grid[:, 0:2] /= CELL_SIZE - transformed_cloud = np.dot(cloud, r.T) + alignments = [] - # Then translate - transformed_cloud[:] += particle[0:2] + plt.imshow(grid, origin='lower') + # plt.scatter(cloud_on_grid[:, 0], cloud_on_grid[:, 1], c='red', s=1.0) - # Translate relative to map origin - transformed_cloud = np.subtract(transformed_cloud, self.map_origin) + particles_on_grid = [] - # Scale to cells - transformed_cloud /= self.grid_resolution + for particle in particles: + # particle_on_grid = np.copy(particle) - # # Round each point in the cloud down to an int - # # Now each point represents an index in cells. Convenient! - grid_indices = transformed_cloud.astype(int) + # Transform particle to grid s.t. x/y are grid indices + particle_on_grid = particle - self.mu + particle_on_grid[0:2] -= GRID_ORIGIN_METERS + particle_on_grid[0:2] /= CELL_SIZE + particle_on_grid = particle_on_grid.astype(int) - start = time.time() + # Rotate cloud to particle frame - hits = 0 + cloud_on_particle = np.copy(cloud_on_grid) + cloud_on_particle[:, 0:2] += GRID_ORIGIN_METERS/CELL_SIZE + d_theta = particle_on_grid[2] + r = np.array([[np.cos(d_theta), -1*np.sin(d_theta)], + [np.sin(d_theta), np.cos(d_theta)]]) + cloud_on_particle[:, 0:2] = np.dot( + cloud_on_particle[:, 0:2], r.T) # Apply rotation matrix + # cloud_on_grid[:, 0:2] -= GRID_ORIGIN_METERS/CELL_SIZE + + # Translate cloud to complete transform + cloud_on_particle[:, 0:2] += particle_on_grid[0:2] + cloud_on_particle = cloud_on_particle.astype(int) - for index in grid_indices[::100]: - if index[0] >= cells.shape[0] or index[1] >= cells.shape[1]: + hits = 0 + good_points = [] + bad_points = [] + for pt in cloud_on_particle: + if pt[0] >= grid.shape[0] or pt[1] >= grid.shape[1] or pt[0] < 0 or pt[1] < 0: continue - if cells[index[1], index[0]] == 100: + if grid[pt[1]][pt[0]] == 100 and pt[2] == ROAD_ID: hits += 1 - - alignments.append(hits) - - alignments = np.array(alignments) - - particles[:, 2] = gnss_pose[2] - - weights *= alignments - dists = np.linalg.norm(particles[:, 0:2] - gnss_pose[0:2], axis=1) - weights[dists > 4.0] *= 0.1 # Penalize particles too far from the GNSS + good_points.append(pt) + elif grid[pt[1]][pt[0]] == 100 and (pt[2] == POLE_ID or pt[2] == TRAFFIC_LIGHT_ID): + # Pole and traffic light misalignment penalty + # Poles and traffic lights should not fall into roads, so penalize particles that present this + hits -= 5 + else: + bad_points.append(pt) + alignments.append(hits / len(cloud_on_particle)) + + bad_points = np.array(bad_points) + good_points = np.array(good_points) + # plt.scatter(particle_on_grid[0], particle_on_grid[1], c='blue') + # # # print(cloud_on_particle) + + particles_on_grid.append(particle_on_grid) + + if not DO_PLOT_ALIGNMENT: + continue # Skip to next loop if plotting not enabled + + if len(bad_points) > 1: + plt.scatter(bad_points[:, 0], + bad_points[:, 1], s=1.0, c='red') + if len(good_points) > 1: + plt.scatter(good_points[:, 0], + good_points[:, 1], s=1.0, c='green') + + particles_on_grid = np.array(particles_on_grid) + + if DO_PLOT_ALIGNMENT: + print(np.max(alignments) / len(cloud)) + plt.scatter(particles_on_grid[:, 0], + particles_on_grid[:, 1], c=alignments) + + plt.colorbar() + plt.show() + + # alignments = np.array(alignments) / len(particles) + + # # if np.max(alignments) > 0.5: + # # weights *= alignments + # # else: + # # print(f"Max alignment was only {np.max(alignments)}") + # weights *= alignments weights += 1.e-300 # avoid round-off to zero weights /= sum(weights) # normalize + return alignments + def estimate(self, particles: np.array, weights) -> tuple: """Return mean and variance of particles @@ -196,42 +275,183 @@ def create_uniform_particles(self, x_range, y_range, hdg_range, N: int) -> np.ar particles[:, 2] %= 2 * np.pi return particles - def __init__(self, grid: np.array, grid_resolution: float, initial_pose=np.array([0.0, 0.0, 0.0]), map_origin=np.array([0.0, 0.0]), N=100): + def __init__(self, clock, grid_resolution: float, initial_pose=np.array([0.0, 0.0, 0.0]), map_origin=np.array([0.0, 0.0]), N=30): self.particles = self.create_gaussian_particles( mean=initial_pose, std=(2, 2, np.pi/8), N=N) self.weights = np.ones(N) / N + self.alignment_history = None + self.mu = initial_pose - self.grid = grid self.map_origin = map_origin self.grid_resolution = grid_resolution - def reset(self, initial_pose=np.array([0.0, 0.0, 0.0]), N=100): + self.mus = [] + self.gnss_poses = [] + self.last_update_time = clock + self.previous_speed = 0.0 + + def reset(self, initial_pose, N): self.particles = self.create_gaussian_particles( mean=initial_pose, std=(2, 2, np.pi/8), N=N) self.weights = np.ones(N) / N - def step(self, delta: np.array, cloud: np.array, gnss_pose: np.array) -> tuple: + def addNoise(self, particles, std, N): + threshold = 1/N + + low_particles = particles[self.weights < threshold] + low_N = len(low_particles) + + print(f"Adding noise to {low_N} particles") + particles[self.weights < threshold][:, 0] += (randn(low_N) * std[0]) + particles[self.weights < threshold][:, 1] += (randn(low_N) * std[1]) + particles[self.weights < threshold][:, 2] += (randn(low_N) * std[2]) + particles[self.weights < threshold][:, 2] %= 2 * np.pi - self.predict(self.particles, delta, std=np.array([0.0, 0.0, 0.0])) + def sense(self, cloud, noise): - self.update_weights(self.particles, self.weights, - cloud, self.grid, gnss_pose) + MAX_LANDMARK_DIST = 10.0 # meters + + traffic_light_pts = cloud[cloud[:, 2] == TRAFFIC_LIGHT_ID][:, 0:2] + + # Filter out faraway pts + traffic_light_pts = traffic_light_pts[np.linalg.norm( + traffic_light_pts, axis=1) < MAX_LANDMARK_DIST] + + downsampled_pts = [] + + # Only include points not super close to other ones + MIN_DISTANCE = 1.0 # Points closer than this will be simplified to one pt + for pt_a in traffic_light_pts: + too_close = False + for pt_b in downsampled_pts: + if np.linalg.norm(pt_a - pt_b) < MIN_DISTANCE: + too_close = True + break + if not too_close: + downsampled_pts.append(pt_a) + + downsampled_pts = np.array(downsampled_pts) + + print("Traffic light points:") + print(downsampled_pts) + + downsampled_pts = downsampled_pts.reshape((-1, 2)) + + distances = np.linalg.norm( + downsampled_pts, axis=1) + randn(downsampled_pts.shape[0]) * noise + + return distances + + def getLandmarks(self, grid, mu): + # plt.imshow(grid, origin='lower') + # plt.show() + landmarks_on_grid = np.flip( + np.transpose((grid == 13).nonzero()), axis=1) + + if landmarks_on_grid.shape[0] == 0: + return landmarks_on_grid # If empty, send it out + + print(landmarks_on_grid) + # landmarks_on_grid = landmarks_on_grid[landmarks_on_grid[:, 0] > 70] + # landmarks_on_grid = landmarks_on_grid[landmarks_on_grid[:, 0] < 85] + # landmarks_on_grid = landmarks_on_grid[landmarks_on_grid[:, 1] < 70] + # landmarks_on_grid = landmarks_on_grid[landmarks_on_grid[:, 1] > 60] + + landmarks_on_map = landmarks_on_grid * CELL_SIZE + landmarks_on_map += GRID_ORIGIN_METERS + + # Rotate to map + d_theta = -1 * mu[2] # Invert to get base_link->map rotation + r = np.array([[np.cos(d_theta), -1*np.sin(d_theta)], + [np.sin(d_theta), np.cos(d_theta)]]) + landmarks_on_map[:, 0:2] = np.dot( + landmarks_on_map[:, 0:2], r.T) # Apply rotation matrix + + # Now translate + landmarks_on_map += mu[0:2] + + print(landmarks_on_map) + + # plt.scatter(landmarks_on_map[:, 0], landmarks_on_map[:, 1]) + # plt.scatter(mu[0], mu[1], c='r') + # plt.show() + + return landmarks_on_map + + def resample(self, particles, alignments, gnss_pose): + + alignments = np.array(alignments).reshape((-1, 1)) + + # Kill off particles further than 5m from GNSS + dists = gnss_difference = np.linalg.norm( + particles[:, 0:2] - gnss_pose[0:2], axis=1) + alignments[dists > 5] = 0. + + # Form a combined particle-alignment array + combined_array = np.hstack((particles, alignments)) + # Sort by third column (alignments) + combined_array = combined_array[combined_array[:, 3].argsort()] + + # Determine the number of particles to be replaced + replacement_qty = int(len(particles)/10) + + # Perform replacement + print(f"Replacing bottom {replacement_qty} particles") + combined_array[0:replacement_qty] = combined_array[- + 1*replacement_qty-1:-1] + + # Add a little noise + print(randn(replacement_qty).T) + print(combined_array[0: replacement_qty, 0]) + combined_array[0: replacement_qty, + 0] += randn(replacement_qty).T * 0.1 + combined_array[0: replacement_qty, + 1] += randn(replacement_qty).T * 0.1 + + print(combined_array) + + # Return only the particles, not the alignments + return combined_array[:, 0: 3] + + def step(self, u, clock, cloud: np.array, gnss_pose: np.array, grid: np.array) -> tuple: + """Takes new data, runs it through the filter, and generates a result pose. + + ✅ 1. Predict the motion of all particles using the latest speedometer and angular velocity data. + ✅ 2. Assign a likelihood score to each particle using the latest classified cloud and grid. + ❌ 3. Select and replace the bottom X percent of particles with copies of the top X percent + ✅ 4. Take the weighted mean and covariance of the particles, return them + ✅ 5. Repeat 1-4. + + Returns: + (mean, covariance) + """ + + self.predictMotion(self.particles, u, std=[ + 0.3, 0.05], dt=clock - self.last_update_time, new_heading=gnss_pose[2]) + self.last_update_time = clock + + alignments = self.updateWeights(self.particles, self.weights, + cloud, grid, gnss_pose) + + self.particles = self.resample(self.particles, alignments, gnss_pose) - # Determine if a resample is necessary - # N/2 is a good threshold - N = len(self.particles) - if self.neff(self.weights) < N/2: - indexes = self.systematic_resample(self.weights) - self.resample_from_index(self.particles, self.weights, indexes) - assert np.allclose(self.weights, 1/N) mu, var = self.estimate(self.particles, self.weights) gnss_difference = np.linalg.norm(mu - gnss_pose) + if gnss_difference > 3: + print("KIDNAPPED! Reseting.") + self.reset(gnss_pose, N=len(self.particles)) + + self.mu = mu + + self.mus.append(mu) + self.gnss_poses.append(gnss_pose) - if gnss_difference > 5: - self.reset(gnss_pose, N=100) + # plt.plot(self.mus) + # plt.plot(self.gnss_poses) + # plt.show() return mu, var diff --git a/src/perception/state_estimation/state_estimation/mcl_node.py b/src/perception/state_estimation/state_estimation/mcl_node.py index 7e5b13261..721560a98 100644 --- a/src/perception/state_estimation/state_estimation/mcl_node.py +++ b/src/perception/state_estimation/state_estimation/mcl_node.py @@ -19,12 +19,17 @@ ''' import math - import numpy as np import rclpy import ros2_numpy as rnp +import struct +import time + +# Message definitions +from carla_msgs.msg import CarlaSpeedometer from geometry_msgs.msg import TransformStamped from nav_msgs.msg import OccupancyGrid, Odometry +from nova_msgs.srv import GetLandmarks from rclpy.node import Node from rosgraph_msgs.msg import Clock from sensor_msgs.msg import Imu, PointCloud2 @@ -32,47 +37,85 @@ from .mcl import MCL +import matplotlib.pyplot as plt + class MCLNode(Node): def __init__(self): super().__init__('mcl_node') + self.previous_result = None self.clock = Clock() self.filter = None self.gnss_pose = None + self.last_update_time = time.time() self.old_gnss_pose = None self.grid: np.array = None + self.imu = None + self.speed: float = 0.0 # m/s self.clock_sub = self.create_subscription( Clock, '/clock', self.clock_cb, 10) self.cloud_sub = self.create_subscription( - PointCloud2, '/lidar_semantic_filtered', self.cloud_cb, 10) + PointCloud2, '/lidar/semantic', self.cloud_cb, 10) self.gnss_sub = self.create_subscription( Odometry, '/odometry/gnss_processed', self.gnss_cb, 10) + self.imu_sub = self.create_subscription( + Imu, '/carla/hero/imu', self.imu_cb, 10) + self.map_sub = self.create_subscription( OccupancyGrid, '/grid/drivable', self.map_cb, 10) + self.speed_sub = self.create_subscription( + CarlaSpeedometer, '/carla/hero/speedometer', self.speed_cb, 1) + self.particle_cloud_pub = self.create_publisher( PointCloud2, '/mcl/particles', 10) + # landmark_request = GetLandmarks.Request() + # self.get_logger().info("Sending request") + # self.landmarks: GetLandmarks.Response = self.landmark_client.call( + # landmark_request) + # self.get_logger().info( + # f"Received {len(self.landmarks.speed_limit_signs)} speed limit signs") + + self.landmark_client = self.create_client( + GetLandmarks, 'get_landmarks') + + # landmark_request = GetLandmarks.Request() + # self.get_logger().info("Sending request") + # self.landmarks: GetLandmarks.Response = self.landmark_client.call( + # landmark_request) + # self.get_logger().info( + # f"Received {len(self.landmarks.speed_limit_signs)} speed limit signs") self.tf_broadcaster = TransformBroadcaster(self) def clock_cb(self, msg: Clock): self.clock = msg - def get_motion_delta(self, old_pose, current_pose): - if old_pose is None: - return np.zeros(3) + def imu_cb(self, msg: Imu): + self.imu = msg + + def speed_cb(self, msg: CarlaSpeedometer): + self.speed = msg.speed - delta = current_pose-old_pose - # delta[2] *= -1 # Why? I don't know + def getMotionDelta(self, current_gnss_pose, old_gnss_pose, speed: float, dt): + # Start by calculating heading change + delta = np.zeros((3)) + delta[2] = current_gnss_pose[2] - old_gnss_pose[2] # Wrap heading to [0, 2*pi] delta[2] %= 2*np.pi + + # Now calculate displacement via speedometer and dt + displacement = speed * dt # result in meters + delta[0] = displacement * np.cos(current_gnss_pose[2]) + delta[1] = displacement * np.sin(current_gnss_pose[2]) + return delta def publish_particle_cloud(self): @@ -102,23 +145,44 @@ def cloud_cb(self, msg: PointCloud2): """ # Wait until filter is created - if self.filter is None: + if self.filter is None or self.imu is None: return + if self.previous_result is None: + self.previous_result = np.zeros((3)) + # Change in pose since last filter update - delta = self.get_motion_delta(self.old_gnss_pose, self.gnss_pose) + dt = time.time() - self.last_update_time + heading_rate = self.imu.angular_velocity.z # The filter accepts clouds as a (N,2) array. Format accordingly. cloud_formatted = rnp.numpify(msg) - cloud = np.vstack((cloud_formatted['x'], cloud_formatted['y'])).T + + ROAD_ID = 4286595200 + TRAFFIC_LIGHT_ID = 4294617630 + POLE_ID = 4288256409 + + cloud_formatted = cloud_formatted[np.logical_or(cloud_formatted['rgb'] == POLE_ID, + np.logical_or(cloud_formatted['rgb'] == ROAD_ID, + cloud_formatted['rgb'] == TRAFFIC_LIGHT_ID))] + + cloud = np.vstack( + (cloud_formatted['x'], cloud_formatted['y'], cloud_formatted['rgb'])).T + + # Filter to road points only # step() is the critical function that feeds data into the filter # and returns a pose and covariance. + + clock_seconds = self.clock.clock.sec + self.clock.clock.nanosec * 1e-9 + result_pose, pose_variance = self.filter.step( - delta, cloud, self.gnss_pose) + [heading_rate, self.speed], clock_seconds, cloud, self.gnss_pose, self.grid) + + self.last_update_time = time.time() self.publish_particle_cloud() - self.get_logger().info(f"Diff: {str(self.gnss_pose-result_pose)}") + # self.get_logger().info(f"Diff: {str(self.gnss_pose-result_pose)}") # Turn our filter result into a transform t = TransformStamped() @@ -132,13 +196,15 @@ def cloud_cb(self, msg: PointCloud2): # Broadcast our transform self.tf_broadcaster.sendTransform(t) + # self.get_logger().info("BROADCASTING") # Cache our gnss_pose to calculate the delta later - self.old_gnss_pose = self.gnss_pose + self.previous_result = result_pose def gnss_cb(self, msg: Odometry): pose_msg = msg.pose.pose yaw = 2*math.asin(pose_msg.orientation.z) + self.old_gnss_pose = self.gnss_pose self.gnss_pose = np.array([ pose_msg.position.x, pose_msg.position.y, @@ -146,18 +212,26 @@ def gnss_cb(self, msg: Odometry): ]) def map_cb(self, msg: OccupancyGrid): - if self.grid is not None: - return # Exit if the map is already initialized + data = np.rot90(np.array(msg.data).reshape(151, 151), k=1, axes=(1, 0)) + # plt.imshow(data, origin='lower') + # print("Showing!") + # plt.show() + if self.gnss_pose is None: return # Wait for initial guess from GNSS self.grid = np.asarray(msg.data, dtype=np.int8).reshape(msg.info.height, msg.info.width) + if self.filter is not None: + return + origin = msg.info.origin.position res = msg.info.resolution - self.filter = MCL(self.grid, res, initial_pose=self.gnss_pose, - map_origin=np.array([origin.x, origin.y])) + + clock_seconds = self.clock.clock.sec + self.clock.clock.nanosec * 1e-9 + self.filter = MCL(clock_seconds, res, initial_pose=self.gnss_pose, + map_origin=np.array([origin.x, origin.y]), N=50) self.get_logger().info("MCL filter created") diff --git a/src/planning/cost_map_maker/CMakeLists.txt b/src/planning/cost_map_maker/CMakeLists.txt deleted file mode 100755 index ab315b803..000000000 --- a/src/planning/cost_map_maker/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# Filename: CMakeLists.txt -# Author: Chitsein Htun -# Email: chtun@live.com -# Copyright: 2021, Nova UTD -# License: MIT License - -# No package name is specified above since this is our standard -# CMakeLists.txt file and will be the same across multiple -# projects. To use it, just add nova_auto_package as a -# buildtool_depend in package.xml and copy this file into the root of -# your package. - -cmake_minimum_required(VERSION 3.5) -get_filename_component(directory_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) -project(${directory_name}) - -find_package(nova_auto_package REQUIRED) - -# Default to C++17 -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) -endif() - -nova_auto_package() diff --git a/src/planning/cost_map_maker/design/CostMapMakerNode.md b/src/planning/cost_map_maker/design/CostMapMakerNode.md deleted file mode 100755 index e51d9b6e9..000000000 --- a/src/planning/cost_map_maker/design/CostMapMakerNode.md +++ /dev/null @@ -1,11 +0,0 @@ -Cost Map Maker {#cost-map-maker} -=========== - -This is the design document for the `cost_map_maker` package. - -# Purpose / Use cases -The cost map maker is used to create a cost map in a useable format for a path planner to decide which paths are least 'costly' based on factors such as safety, following traffic laws, using proper/good traffic protocols, etc. - -The cost map maker takes in a dynamic occupancy grid in order to determine which paths are safe or follow traffic laws and outputs a cost map that tells the vehicle what areas should be avoided, which is passed to the motion planner. - -The cost map maker takes in a velocity of the vehicle and passes it to the motion planner so that it knows what are achievable velocities of a car at each time step 't'. \ No newline at end of file diff --git a/src/planning/cost_map_maker/exe/cost_map_maker.cpp b/src/planning/cost_map_maker/exe/cost_map_maker.cpp deleted file mode 100755 index fb124770f..000000000 --- a/src/planning/cost_map_maker/exe/cost_map_maker.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Package: cost_map_maker - * Filename: cost_map_maker.cpp - * Author: Chitsein Htun - * Email: chtun@live.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -#include // std::make_shared -#include "rclcpp/rclcpp.hpp" -#include "cost_map_maker/CostMapMakerNode.hpp" - -int main(int argc, char ** argv) { - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} diff --git a/src/planning/cost_map_maker/include/cost_map_maker/CostMapMakerNode.hpp b/src/planning/cost_map_maker/include/cost_map_maker/CostMapMakerNode.hpp deleted file mode 100755 index 54fdd05ba..000000000 --- a/src/planning/cost_map_maker/include/cost_map_maker/CostMapMakerNode.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Package: MotionPlanner - * Filename: MotionPlanner.hpp - * Author: Jim Moore - * Email: jim3moore@gmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -/* - Currently, this node gets an Evidential Grid Map input from perception and creates a cost map accordingly to ensure safety and good driving practices. - It does so by giving collisions an extremely high costs and making spaces closer to the next waypoint less costly. *TO BE CONTINUED* -*/ - -#pragma once - -#include // Time literals -#include -#include - -// libOpenDRIVE includes -#include "OpenDriveMap.h" -#include "Lanes.h" -#include "Road.h" -#include "Geometries/Line.h" -#include "RefLine.h" -#include "opendrive_utils/OpenDriveUtils.hpp" - -// Message includes -#include "rclcpp/rclcpp.hpp" -#include -#include -#include -#include -#include "nova_msgs/msg/egma.hpp" -#include "nova_msgs/msg/evidential_grid.hpp" -#include -#include - -using namespace std::chrono_literals; - -namespace navigator { -namespace cost_map_maker { - -// How often to publish the new trajectory message -constexpr auto message_frequency = 250ms; - -class CostMapMakerNode : public rclcpp::Node { -public: - // Constructor - CostMapMakerNode(); - - // Functions - -private: - - // Send final cost map to subscribers - void send_message(); - // Subscription to *INSERT PUBLISHER* for input Evidential Grid Map - void update_egma(nova_msgs::msg::Egma::SharedPtr ptr); - // Subscription to *INSERT PUBLISHER* for input waypoints - void update_waypoints(geometry_msgs::msg::Vector3::SharedPtr ptr); - // Subscription to *INSERT PUBLISHER* for the current heading of the car - void odometry_pose_cb(const nav_msgs::msg::Odometry::SharedPtr msg); - - // Cost Map Publisher - rclcpp::Publisher::SharedPtr cost_map_publisher; - // Evidential Grid Map Subscriber - rclcpp::Subscription::SharedPtr egma_subscription; - /* TODO Add information from global waypoints */ - rclcpp::Subscription::SharedPtr waypoint_subscription; - - // Odometry Subscriber - rclcpp::Subscription::SharedPtr odomtery_pose_subscription; - // Timer - rclcpp::TimerBase::SharedPtr control_timer; - - - // EGMa from prediction - nova_msgs::msg::Egma::SharedPtr egma; - - /* TODO Add information from global waypoints */ - navigator::opendrive::OpenDriveMapPtr carla_map; - geometry_msgs::msg::Vector3::SharedPtr waypoints; - nav_msgs::msg::Odometry::SharedPtr odometry; -}; -} -} diff --git a/src/planning/cost_map_maker/package.xml b/src/planning/cost_map_maker/package.xml deleted file mode 100755 index 34a9fe19f..000000000 --- a/src/planning/cost_map_maker/package.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - cost_map_maker - 0.0.1 - Cost Map Maker - Jim Moore - MIT - - nova_auto_package - boost_geometry - had_map_utils - motion_common - tf2 - tf2_ros - nova_msgs - rclcpp - geometry_msgs - nav_msgs - zone_lib - libopendrive - - - - ament_cmake - - diff --git a/src/planning/cost_map_maker/src/CostMapMakerNode.cpp b/src/planning/cost_map_maker/src/CostMapMakerNode.cpp deleted file mode 100755 index 9f4e4bc4c..000000000 --- a/src/planning/cost_map_maker/src/CostMapMakerNode.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Package: MotionPlanner - * Filename: MotionPlanner.hpp - * Author: Jim Moore - * Email: jim3moore@gmail.com - * Copyright: 2022, Nova UTD - * License: MIT License - */ - -//NOTE: LOOK IN HEADER FILE FOR COMMENTS ON FUNCTION DEFINITIONS - -//#include - -#include "rclcpp/rclcpp.hpp" -#include - -#include "cost_map_maker/CostMapMakerNode.hpp" - -#include -#include - -using namespace navigator::cost_map_maker; - -using nova_msgs::msg::Egma; -using nova_msgs::msg::EvidentialGrid; -using geometry_msgs::msg::Vector3; - -CostMapMakerNode::CostMapMakerNode() : Node("cost_map_maker_node") -{ - std::string xodr_path = "data/maps/town07/Town07_Opt.xodr"; - - cost_map_publisher = this->create_publisher("outgoing_cost_map", 8); - egma_subscription = this->create_subscription("*INSERT SUBSCRIPTION*", 10, bind(&CostMapMakerNode::update_egma, this, std::placeholders::_1)); - waypoint_subscription = this->create_subscription("*INSERT SUBSCRIPTION*", 10, bind(&CostMapMakerNode::update_waypoints, this, std::placeholders::_1)); - odomtery_pose_subscription = this->create_subscription("/carla/odom", rclcpp::QoS(10),std::bind(&CostMapMakerNode::odometry_pose_cb, this, std::placeholders::_1)); - control_timer = this->create_wall_timer(message_frequency, bind(&CostMapMakerNode::send_message, this)); - - // Read map from file, using our path param - RCLCPP_INFO(this->get_logger(), "Reading from ", xodr_path.c_str()); - carla_map = navigator::opendrive::load_map(xodr_path)->map; -} - -void CostMapMakerNode::send_message() { - if (egma == nullptr) { - return; - } - - auto cost_map = nova_msgs::msg::Egma(); - for (size_t time_index = 0; time_index < egma->egma.size(); time_index++) { - auto cost_map_single_timestep = nova_msgs::msg::EvidentialGrid(); - auto current_evidential_grid = egma->egma[time_index]; - cost_map_single_timestep.header = current_evidential_grid.header; - for (size_t coordinate_index = 0; coordinate_index < current_evidential_grid.grid.size(); coordinate_index++) - { - cost_map_single_timestep.grid[coordinate_index].occupancy_value = current_evidential_grid.grid[coordinate_index].occupancy_value; - cost_map_single_timestep.grid[coordinate_index].occupancy_value = current_evidential_grid.grid[coordinate_index].occupancy_value; - } - cost_map.egma.push_back(cost_map_single_timestep); - } - cost_map_publisher->publish(cost_map); - - - return; -} - -void CostMapMakerNode::update_egma(nova_msgs::msg::Egma::SharedPtr ptr) { - egma = ptr; -} - -void CostMapMakerNode::update_waypoints(geometry_msgs::msg::Vector3::SharedPtr ptr) -{ - waypoints = ptr; -} - -void CostMapMakerNode::odometry_pose_cb(const nav_msgs::msg::Odometry::SharedPtr msg) { - odometry = msg; -} \ No newline at end of file diff --git a/src/planning/cost_map_maker/test/test_cost_map_maker.cpp b/src/planning/cost_map_maker/test/test_cost_map_maker.cpp deleted file mode 100755 index 2edda10da..000000000 --- a/src/planning/cost_map_maker/test/test_cost_map_maker.cpp +++ /dev/null @@ -1,220 +0,0 @@ -// /* -// * Package: motion_planner -// * Filename: test_OpenDriveUtils.hpp -// * Author: Egan Johnson -// * Email: egan.johnson@utdallas.edu -// * Copyright: 2022, Nova UTD -// * License: MIT License -// */ - -// #include -// #include - -// #include "zone_lib/zone.hpp" -// #include "motion_planner/MotionPlannerNode.hpp" -// using namespace navigator::motion_planner; -// using nova_msgs::msg::Trajectory; -// using nova_msgs::msg::TrajectoryPoint; -// using nova_msgs::msg::Zone; -// using nova_msgs::msg::ZoneArray; - -// /** -// * @brief Creates a simple trajectory -// * with 10 points interspaced 1m apart -// * on the x-axis, starting at 0.0. Points -// * are set to an arbitrary speed of 1.0. -// * -// * Creates an empty zone array. -// * -// */ -// class SimplePathTest : public ::testing::Test -// { -// public: -// Trajectory trajectory; -// ZoneArray zone_array; - -// SimplePathTest(){ -// trajectory.points.resize(10); -// for(int i = 0; i < 10; i++){ -// trajectory.points[i].x = i; -// trajectory.points[i].y = 0.0; -// trajectory.points[i].vx = 1.0; -// } -// zone_array.zones.resize(0); -// } -// }; - -// TEST_F(SimplePathTest, test_zone_boundary){ -// // Creates a square with side length 1.0 -// // aligned with the cooridinate axis and centered -// // at (5, 0). When the path is smoothed to this zone, -// // we expect two additional points to be added to the -// // path: (4.5, 0) and (5.5, 0). If we set the zone -// // speed to 0, we expect the speeds to be 0 for points -// // (4.5, 0), (5, 0), and (5.5, 0). -// Zone zone; -// zone.poly.points.resize(4); -// zone.poly.points[0].x = 4.5; -// zone.poly.points[0].y = 0.5; -// zone.poly.points[1].x = 5.5; -// zone.poly.points[1].y = 0.5; -// zone.poly.points[2].x = 5.5; -// zone.poly.points[2].y = -0.5; -// zone.poly.points[3].x = 4.5; -// zone.poly.points[3].y = -0.5; - -// zone.max_speed = 0.0; - -// zone_array.zones.push_back(zone); - -// Trajectory traj1(trajectory); -// MotionPlannerNode::smooth(traj1, zone_array, 1.0, 1.0); -// EXPECT_EQ(traj1.points.size(), 12ul); -// EXPECT_NEAR(traj1.points[5].x, 4.5, 0.00001); -// EXPECT_NEAR(traj1.points[5].y, 0.0, 0.00001); -// EXPECT_NEAR(traj1.points[5].vx, 0.0, 0.00001); -// EXPECT_NEAR(traj1.points[6].x, 5.0, 0.00001); -// EXPECT_NEAR(traj1.points[6].y, 0.0, 0.00001); -// EXPECT_NEAR(traj1.points[6].vx, 0.0, 0.00001); -// EXPECT_NEAR(traj1.points[7].x, 5.5, 0.00001); -// EXPECT_NEAR(traj1.points[7].y, 0.0, 0.00001); -// EXPECT_NEAR(traj1.points[7].vx, 0.0, 0.00001); - -// for (TrajectoryPoint point : traj1.points){ -// std::cout << "(" < STALENESS_TOLERANCE + if stale: + if status.level == DiagnosticStatus.OK: + status.level = DiagnosticStatus.WARN + status.message = "Current occupancy was stale." + else: + status.level = DiagnosticStatus.ERROR + status.message = "More than one layer was stale!" + + def getWeightedArray(self, msg: OccupancyGrid, scale: float) -> np.ndarray: + """Converts the OccupancyGrid message into a numpy array, then multiplies it by scale + + Args: + msg (OccupancyGrid) + scale (float) + + Returns: + np.ndarray: Weighted ndarray + """ + arr = np.asarray(msg.data, dtype=np.float16).reshape( + msg.info.height, msg.info.width) + + arr *= scale + + return arr + + def resizeOccupancyGrid(self, original: np.ndarray) -> np.ndarray: + # This is a temporary measure until our current occ. grid's params + # match the rest of our stack. Basically, due to the difference in cell size, + # 1 out of 6 cells in the array needs to be deleted. + + downsampled = np.delete(original, np.arange(0, 128, 6), axis=0) + downsampled = np.delete(downsampled, np.arange( + 0, 128, 6), axis=1) # 106x106 result + + # trim the bottom columns (behind the car) + downsampled = downsampled[:, 3:] + + background = np.zeros((151, 151)) + + background[22:128, 0:103] = downsampled + return background # Correct scale + + def createCostMap(self): + status = DiagnosticStatus() + status.level = DiagnosticStatus.OK + status.name = 'grid_summation' + + steering_cost = np.zeros((151, 151)) + speed_cost = np.zeros((151, 151)) + + # Calculate the weighted cost map layers + + # 1. Current occupancy + stale = self.checkForStaleness(self.current_occupancy_grid, status) + empty = len(self.current_occupancy_grid.data) == 0 + + weighted_current_occ_arr = None + + if not stale and not empty: + msg = self.current_occupancy_grid + weighted_current_occ_arr = self.getWeightedArray( + msg, CURRENT_OCCUPANCY_SCALE) + weighted_current_occ_arr = self.resizeOccupancyGrid( + weighted_current_occ_arr) + steering_cost += weighted_current_occ_arr + speed_cost += weighted_current_occ_arr + + # 2. Future occupancy + stale = self.checkForStaleness(self.future_occupancy_grid, status) + empty = len(self.future_occupancy_grid.data) == 0 + + if not stale and not empty: + msg = self.future_occupancy_grid + weighted_future_occ_arr = self.getWeightedArray( + msg, FUTURE_OCCUPANCY_SCALE) + weighted_future_occ_arr = self.resizeOccupancyGrid( + weighted_future_occ_arr) + steering_cost += weighted_future_occ_arr + speed_cost += weighted_future_occ_arr + + # 3. Drivable area + stale = self.checkForStaleness(self.drivable_grid, status) + empty = len(self.drivable_grid.data) == 0 + + if not stale and not empty: + msg = self.drivable_grid + weighted_drivable_arr = self.getWeightedArray( + msg, DRIVABLE_GRID_SCALE) + steering_cost += weighted_drivable_arr + # speed_cost += weighted_drivable_arr + + # 4. Route distance + stale = self.checkForStaleness(self.route_dist_grid, status) + empty = len(self.route_dist_grid.data) == 0 + + if not stale and not empty: + msg = self.route_dist_grid + weighted_route_dist_arr = self.getWeightedArray( + msg, ROUTE_DISTANCE_GRID_SCALE) + steering_cost += weighted_route_dist_arr + + # 5. Junctions + stale = self.checkForStaleness(self.junction_grid, status) + empty = len(self.junction_grid.data) == 0 + + if not stale and not empty and weighted_current_occ_arr is not None: + msg = self.junction_grid + weighted_junction_arr = self.getWeightedArray( + msg, JUNCTION_GRID_SCALE) + + speed_cost += weighted_junction_arr + + # Cap this to 100 + steering_cost = np.clip(steering_cost, 0, 100) + speed_cost = np.clip(speed_cost, 0, 100) + + # plt.show() + + # Publish as an OccupancyGrid + result_msg = OccupancyGrid() + + result_msg.data = steering_cost.astype(np.int8).flatten().tolist() + result_msg.info = self.drivable_grid.info + result_msg.header = self.drivable_grid.header + + self.steering_cost_pub.publish(result_msg) + + result_msg.data = speed_cost.astype(np.int8).flatten().tolist() + self.speed_cost_pub.publish(result_msg) + + egma_msg = Egma() + egma_msg.header = result_msg.header + + current_stamp = result_msg.header.stamp + t = current_stamp.sec + current_stamp.nanosec * 1e-9 + for i in range(15): + frame = result_msg + + t += 0.1 # dt = 0.1 seconds + next_stamp = current_stamp + next_stamp.sec = int(t) + next_stamp.nanosec = int(t * 1e9 % 1e9) + + result_msg.header.stamp = next_stamp + result_msg.header.frame_id = 'base_link' + + egma_msg.egma.append(frame) + + self.combined_egma_pub.publish(egma_msg) + + +def main(args=None): + rclpy.init(args=args) + + grid_summation_node = GridSummationNode() + + rclpy.spin(grid_summation_node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + grid_summation_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/planning/costs/costs/junction_manager.py b/src/planning/costs/costs/junction_manager.py new file mode 100755 index 000000000..538e3e183 --- /dev/null +++ b/src/planning/costs/costs/junction_manager.py @@ -0,0 +1,263 @@ +''' +Package: grids + File: junction_manager.py + Author: Will Heitman (w at heit dot mn) + +Given a junction grid (where each cell is either within an intersection or not), +plus the current ego speed and occupancy grid, publish a map that either +includes the junction cost or not. This basically switches a junction's +cost on or off, allowing or blocking entrance into junctions based on perception data. + +Subscriptions: +- Junction map (OccupancyGrid) +- Speed (CarlaSpeedometer) +- Current occupancy (OccupancyGrid) + +Publisher: +- "Stafeful" junction map (OccupancyGrid) + - This is either an empty OccupancyGrid (zeros) + or the original junction map. +- Diagnostic status (DiagnosticStatus) + +''' + +from array import array as Array +import rclpy +import ros2_numpy as rnp +import numpy as np +from rclpy.node import Node +import time +from tf2_ros.buffer import Buffer +from tf2_ros.transform_listener import TransformListener + +# Message definitions +from carla_msgs.msg import CarlaSpeedometer +from diagnostic_msgs.msg import DiagnosticStatus +from nav_msgs.msg import OccupancyGrid +from rosgraph_msgs.msg import Clock + +import matplotlib.pyplot as plt + +from skimage.morphology import binary_erosion, square + + +class JunctionManager(Node): + + def __init__(self): + super().__init__('junction_manager') + + self.current_occupancy_grid = None + self.junction_grid = None + self.status = DiagnosticStatus() # TODO: Add status + self.time_sec = 0.0 + self.speed = 0.0 + self.ego_has_stopped = False + self.last_stop_time = 0.0 + self.last_in_junction_time = 0.0 + + # Subscriptions and publishers + self.current_occupancy_sub = self.create_subscription( + OccupancyGrid, '/grid/occupancy/current', self.currentOccupancyCb, 1) + + self.junction_grid_sub = self.create_subscription( + OccupancyGrid, '/grid/junction', self.junctionGridCb, 1) + + self.speed_sub = self.create_subscription( + CarlaSpeedometer, '/carla/hero/speedometer', self.speedometerCb, 1) + + self.stateful_grid_pub = self.create_publisher( + OccupancyGrid, '/grid/stateful_junction', 1) + + self.status_pub = self.create_publisher( + DiagnosticStatus, '/node_statuses', 1) + + self.clock_sub = self.create_subscription( + Clock, '/clock', self.clockCb, 1) + + def speedometerCb(self, msg: CarlaSpeedometer): + self.speed = msg.speed + + def clockCb(self, msg: Clock): + self.time_sec = msg.clock.sec + msg.clock.nanosec * 1e-9 + + def resizeOccupancyGrid(self, original: np.ndarray) -> np.ndarray: + # This is a temporary measure until our current occ. grid's params + # match the rest of our stack. Basically, due to the difference in cell size, + # 1 out of 6 cells in the array needs to be deleted. + + downsampled = np.delete(original, np.arange(0, 128, 6), axis=0) + downsampled = np.delete(downsampled, np.arange( + 0, 128, 6), axis=1) # 106x106 result + + # trim the bottom columns (behind the car) + downsampled = downsampled[:, 3:] + + background = np.zeros((151, 151)) + + background[22:128, 0:103] = downsampled + return background # Correct scale + + def currentOccupancyCb(self, msg: OccupancyGrid): + occupancy_grid = np.asarray(msg.data, + dtype=np.int8).reshape(msg.info.height, msg.info.width) + + occupancy_grid = self.resizeOccupancyGrid(occupancy_grid) + + # This creates a binary array, where each cell is simply "is occupied" or "is not occupied" + self.current_occupancy_grid = occupancy_grid > 80.0 + + def junctionIsOccupied(self, occupancy, junction) -> bool: + # Erode the occupancy grid slightly. + # This "denoises" it, preventing tiny objects from throwing + # false positives. + if occupancy is None: + self.get_logger().warn("Occpancy grid unavailable. Skipping.") + return + + eroded_occupancy = binary_erosion(occupancy) + + # square(5) creates a 5-cell wide erosion region. + # Smaller values erode less. + eroded_junction = binary_erosion(junction, square(1)) + + is_occupied = np.sum(eroded_junction*eroded_occupancy) > 0.0 + + # if is_occupied: + # plt.imshow(eroded_junction*eroded_occupancy, origin='lower') + # plt.scatter(50, 75) + # plt.show() + + return is_occupied + + def egoCanEnter(self, speed: float, occupancy: np.ndarray, junction: np.ndarray) -> bool: + """Can the ego enter the nearest junction? + + Yes iff: + - the ego has stopped (speed less than 0.5 m/s in past 3s) and the junction is not occupied, + - OR the ego is significantly in the junction (beyond the edges) + + If the latter is true yet the junction IS occupied, we rely on object handling beyond + the scope of this node. + + Args: + speed (float): Ego speed, in m/s + occupancy (np.ndarray): Current occupancy grid + junction (np.ndarray): Junction grid + """ + STOP_SPEED_THRESHOLD = 0.5 # m/s + STOP_STALENESS_THRESHOLD = 1.5 # seconds + EGO_CELL = (75, 50) + + can_enter = False + junction_is_occupied = False + in_junction = False + + if speed < STOP_SPEED_THRESHOLD: + self.last_stop_time = self.time_sec + + has_stopped_recently = self.time_sec - \ + self.last_stop_time < STOP_STALENESS_THRESHOLD + + if has_stopped_recently: + junction_is_occupied = self.junctionIsOccupied(occupancy, junction) + if not junction_is_occupied: + can_enter = True + + if not can_enter: + eroded_junction = binary_erosion(junction, square(2)) + + in_junction = eroded_junction[EGO_CELL] == True + + # plt.imshow(eroded_junction) + # plt.show() + + if in_junction: + self.last_in_junction_time = self.time_sec + + was_in_junction_recently = self.time_sec - \ + self.last_in_junction_time < STOP_STALENESS_THRESHOLD + if was_in_junction_recently: + can_enter = True + + # if in_junction: + # print("Already inside junction") + # elif not has_stopped_recently: + # print("Can't enter. Hasn't stopped recently.") + # elif junction_is_occupied: + # print("Can't enter. Junction occupied.") + + return can_enter + + def junctionGridCb(self, msg: OccupancyGrid): + + # The "> 0 " makes this an efficient binary grid + junction_grid = np.asarray(msg.data, + dtype=np.int8).reshape(msg.info.height, msg.info.width) > 0 + + stateful_junction_grid = np.zeros((msg.info.height, msg.info.width)) + + # If the ego cannot enter, set the stateful grid to include the junction cost + if not self.egoCanEnter(self.speed, self.current_occupancy_grid, junction_grid): + stateful_junction_grid = junction_grid.astype(np.int8)*100 + + stateful_msg = OccupancyGrid() + stateful_msg.data = Array( + 'b', stateful_junction_grid.ravel().astype(np.int8)) + stateful_msg.info = msg.info + stateful_msg.header = msg.header + self.stateful_grid_pub.publish(stateful_msg) + + def routeDistGridCb(self, msg: OccupancyGrid): + self.route_dist_grid = msg + + def getWeightedArray(self, msg: OccupancyGrid, scale: float) -> np.ndarray: + """Converts the OccupancyGrid message into a numpy array, then multiplies it by scale + + Args: + msg (OccupancyGrid) + scale (float) + + Returns: + np.ndarray: Weighted ndarray + """ + arr = np.asarray(msg.data, dtype=np.float16).reshape( + msg.info.height, msg.info.width) + + arr *= scale + + return arr + + def resizeOccupancyGrid(self, original: np.ndarray) -> np.ndarray: + # This is a temporary measure until our current occ. grid's params + # match the rest of our stack. Basically, due to the difference in cell size, + # 1 out of 6 cells in the array needs to be deleted. + + downsampled = np.delete(original, np.arange(0, 128, 6), axis=0) + downsampled = np.delete(downsampled, np.arange( + 0, 128, 6), axis=1) # 106x106 result + + # trim the bottom columns (behind the car) + downsampled = downsampled[:, 3:] + + background = np.zeros((151, 151)) + + background[22:128, 0:103] = downsampled + return background # Correct scale + + +def main(args=None): + rclpy.init(args=args) + + junction_manager = JunctionManager() + + rclpy.spin(junction_manager) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + junction_manager.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/mapping/map_management_old/package.xml b/src/planning/costs/package.xml similarity index 78% rename from src/mapping/map_management_old/package.xml rename to src/planning/costs/package.xml index 67740277d..0240e291b 100755 --- a/src/mapping/map_management_old/package.xml +++ b/src/planning/costs/package.xml @@ -1,9 +1,9 @@ - map_management + costs 1.0.0 - Nodes for publishing and processing maps, routes, and related functions. + Package to process, combine, and publish cost maps (grids) Will Heitman MIT @@ -11,8 +11,10 @@ ament_lint_auto ament_lint_common + nav_msgs ament_python + diff --git a/src/planning/costs/resource/costs b/src/planning/costs/resource/costs new file mode 100755 index 000000000..e69de29bb diff --git a/src/planning/costs/setup.cfg b/src/planning/costs/setup.cfg new file mode 100755 index 000000000..98dc83d34 --- /dev/null +++ b/src/planning/costs/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/costs +[install] +install-scripts=$base/lib/costs diff --git a/src/planning/costs/setup.py b/src/planning/costs/setup.py new file mode 100755 index 000000000..4c1526319 --- /dev/null +++ b/src/planning/costs/setup.py @@ -0,0 +1,30 @@ +from setuptools import setup +from glob import glob +import os + +package_name = 'costs' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + (os.path.join('share', package_name), glob('launch/*.launch.py')) + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='main', + maintainer_email='will.heitman@utdallas.edu', + description='Package to process, combine, and publish cost maps', + license='MIT', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'grid_summation_node = costs.grid_summation_node:main', + 'junction_manager = costs.junction_manager:main', + ], + }, +) diff --git a/src/planning/path_publisher/CMakeLists.txt b/src/planning/path_publisher/CMakeLists.txt deleted file mode 100755 index 3ce920c43..000000000 --- a/src/planning/path_publisher/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# Filename: CMakeLists.txt -# Author: Joshua Williams -# Email: joshmackwilliams@protonmail.com -# Copyright: 2021, Nova UTD -# License: MIT License - -# No package name is specified above since this is our standard -# CMakeLists.txt file and will be the same across multiple -# projects. To use it, just add nova_auto_package as a -# buildtool_depend in package.xml and copy this file into the root of -# your package. - -cmake_minimum_required(VERSION 3.5) -get_filename_component(directory_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) -project(${directory_name}) - -find_package(ament_cmake_auto REQUIRED) -ament_auto_find_build_dependencies() - -find_package(nova_auto_package REQUIRED) - -# Default to C++17 -if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 17) -endif() - -nova_auto_package() diff --git a/src/planning/path_publisher/exe/publisher.cpp b/src/planning/path_publisher/exe/publisher.cpp deleted file mode 100755 index a900e20e0..000000000 --- a/src/planning/path_publisher/exe/publisher.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "path_publisher/PathPublisherNode.hpp" - -int main(int argc, char * argv[]) -{ - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} \ No newline at end of file diff --git a/src/planning/path_publisher/include/path_publisher/PathPublisherNode.hpp b/src/planning/path_publisher/include/path_publisher/PathPublisherNode.hpp deleted file mode 100755 index 0565efd24..000000000 --- a/src/planning/path_publisher/include/path_publisher/PathPublisherNode.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -// libOpenDRIVE stuff -#include "OpenDriveMap.h" -#include "Lanes.h" -#include "Road.h" -#include "Geometries/Line.h" -#include "RefLine.h" -#include "opendrive_utils/OpenDriveUtils.hpp" - -// Message headers -#include -#include -#include -#include -#include -#include -#include - -class RouteItem { -public: - RouteItem(std::string road_id, int lane_id) : road_id(road_id), lane_id(lane_id) {} - std::string road_id; - int lane_id; -}; - -class PathPublisherNode : public rclcpp::Node { -public: - PathPublisherNode(); - void generatePaths(); - -private: - std::set all_ids; - - nova_msgs::msg::FinalPath path; - navigator::opendrive::OpenDriveMapPtr map; - double path_resolution; // The sampling interval taken along a lane's centerline to form the path - visualization_msgs::msg::MarkerArray lane_markers; - rclcpp::Subscription::SharedPtr odom_sub; - nav_msgs::msg::Odometry::SharedPtr cached_odom; - rclcpp::Publisher::SharedPtr paths_pub; - rclcpp::Publisher::SharedPtr viz_pub; - rclcpp::TimerBase::SharedPtr path_pub_timer{nullptr}; - - nova_msgs::msg::FinalPath route1; - nova_msgs::msg::FinalPath route2; - - void publish_paths_viz(nova_msgs::msg::FinalPath path); - nova_msgs::msg::FinalPath generate_path(std::vector &road_ids, std::vector &lane_ids, navigator::opendrive::OpenDriveMapPtr map); - void switch_path(nova_msgs::msg::FinalPath path); -}; \ No newline at end of file diff --git a/src/planning/path_publisher/package.xml b/src/planning/path_publisher/package.xml deleted file mode 100755 index 657c537bf..000000000 --- a/src/planning/path_publisher/package.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - path_publisher - 0.0.1 - Package for reading a .xodr file and publishing a MarkerArray message - Will Heitman - MIT - - nova_auto_package - - rclcpp - libopendrive - geometry_msgs - nav_msgs - std_msgs - visualization_msgs - nova_msgs - opendrive_utils - - - ament_cmake - - diff --git a/src/planning/path_publisher/src/PathPublisherNode.cpp b/src/planning/path_publisher/src/PathPublisherNode.cpp deleted file mode 100755 index 14ef4eed7..000000000 --- a/src/planning/path_publisher/src/PathPublisherNode.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -using namespace std; - -#include "path_publisher/PathPublisherNode.hpp" -#include "opendrive_utils/OpenDriveUtils.hpp" - -using geometry_msgs::msg::Point; -using geometry_msgs::msg::Vector3; -using nav_msgs::msg::Odometry; -using std_msgs::msg::ColorRGBA; -using visualization_msgs::msg::Marker; -using visualization_msgs::msg::MarkerArray; -using nova_msgs::msg::FinalPath; -using namespace std::chrono_literals; - -PathPublisherNode::PathPublisherNode() : Node("path_publisher_node") { - - std::string xodr_path = "data/maps/town07/Town07_Opt.xodr"; - paths_pub = this->create_publisher("paths", 1); - odom_sub = this->create_subscription("/odometry/filtered", 1, [this](Odometry::SharedPtr msg) { - cached_odom = msg; - }); - viz_pub = this->create_publisher("path_pub_viz", 1); - - auto route_1_road_ids = std::vector{ - "21","39","57","584","7","693","6","509","5","4", - "686","601","34","532","35","359","40","634","50","10","9","976", - "36","210","46","436","59","168","60","464","61","559","62", - "352","24","467","20","920", - }; - auto route_1_lane_ids = std::vector { - -1,-1,-1,-1,1,1,1,1,1,1, - 1,-1,-1,-1,-1,-1,1,1,-3,-3,-3,-1, - -1,-1,1,1,-1,-1,-1,-1,-1,-1,-1, - -1,-1,-1,-1,-1, - }; - - for (auto s : route_1_road_ids) { - all_ids.insert(s); - } - path_pub_timer = this->create_wall_timer(0.5s, std::bind(&PathPublisherNode::generatePaths, this)); - - // Read map from file, using our path param - RCLCPP_INFO(this->get_logger(), "Reading from ", xodr_path.c_str()); - map = navigator::opendrive::load_map(xodr_path)->map; - - - - this->route1 = generate_path(route_1_road_ids, route_1_lane_ids, map); - this->path = this->route1; -} - -nova_msgs::msg::FinalPath PathPublisherNode::generate_path(std::vector &road_ids, std::vector &lane_ids, navigator::opendrive::OpenDriveMapPtr map) -{ - std::vector route; - FinalPath costed_path; - double step = 0.25; - for (size_t i = 0; i < road_ids.size(); i++) { - std::string id = road_ids[i]; - int lane_id = lane_ids[i]; - auto road = map->roads[id]; - //there is only one lanesection per road on this map - std::shared_ptr lanesection = *(road->get_lanesections().begin()); - odr::LaneSet laneset = lanesection->get_lanes(); - //RCLCPP_INFO(this->get_logger(), "There are %d lanes for road %s", laneset.size(), id.c_str()); - std::shared_ptr lane = nullptr; - //loop through the laneset to find a pointer to the lane. - for (auto l : laneset) { - if (l->id == lane_id) { - lane = l; - break; - } - } - if (lane == nullptr) { - RCLCPP_WARN(this->get_logger(), "NO LANE FOR ROAD %s (i=%d)", id.c_str(), i); - continue; - } - odr::Line3D centerline = navigator::opendrive::get_centerline_as_xy(*lane, lanesection->s0, lanesection->get_end(), step, lane_id>0); - - for (odr::Vec3D point : centerline) { - route.push_back(point); - costed_path.speeds.push_back(10); - } - } - RCLCPP_INFO(this->get_logger(), "generated path"); - - - size_t count = 0; - for (odr::Vec3D pt3d : route) { - Point path_pt; - path_pt.x = pt3d[0]; - path_pt.y = pt3d[1]; - path_pt.z = pt3d[2]; - - count ++; - costed_path.points.push_back(path_pt); - } - return costed_path; -} - -//shamelessly stolen from egan -void PathPublisherNode::publish_paths_viz(FinalPath path) -{ - MarkerArray marker_array; - Marker marker; - - // Set header and identifiers - marker.header.frame_id = "map"; - // marker.header.stamp = this->now(); - marker.ns = "path_pub_viz"; - marker.frame_locked = true; - marker.id = 1; - - // Add data contents - marker.type = Marker::LINE_STRIP; - marker.action = Marker::ADD; - marker.points = path.points; - - // Set visual display. Not sure if this is needed - marker.scale.x = 1; - marker.color.a = 1.0; - marker.color.r = 1.0; - marker.color.g = 1.0; - marker.color.b = 0; - - // Add path to array - marker_array.markers.push_back(marker); - // RCLCPP_INFO(this->get_logger(), "path viz"); - - viz_pub->publish(marker_array); -} - - -void PathPublisherNode::generatePaths() { - // Wait until odometry data is available - if (cached_odom == nullptr) { - RCLCPP_WARN(get_logger(), "Odometry not yet received, skipping..."); - return; - } - Point current_pos = cached_odom->pose.pose.position; - - auto twist = cached_odom->twist.twist.linear; - double speed = std::sqrt(twist.x*twist.x+twist.y*twist.y); - - paths_pub->publish(this->path); - publish_paths_viz(this->path); - - - auto currentLane = navigator::opendrive::get_lane_from_xy_with_route(map, current_pos.x, current_pos.y, all_ids); - if (currentLane == nullptr) { - RCLCPP_WARN(get_logger(), "Lane could not be located."); - return; - } - auto currentRoadId = currentLane->road.lock()->id; - - RCLCPP_INFO(get_logger(), "(%.2f, %.2f) Road %s, Current lane: %i", current_pos.x, current_pos.y, currentRoadId.c_str(), currentLane->id); - //if (currentRoadId == "10" && this->path == this->route1) { - // RCLCPP_INFO(get_logger(), "SWITCHED PATH"); - // this->path = this->route2; - //} -} diff --git a/src/planning/rtp/package.xml b/src/planning/rtp/package.xml new file mode 100755 index 000000000..11754268d --- /dev/null +++ b/src/planning/rtp/package.xml @@ -0,0 +1,19 @@ + + + + rtp + 1.0.0 + Recursive tree planner for path generation + Will Heitman + MIT + + ament_copyright + ament_flake8 + ament_pep257 + carla_msgs + python3-pytest + + + ament_python + + diff --git a/src/planning/rtp/resource/rtp b/src/planning/rtp/resource/rtp new file mode 100755 index 000000000..e69de29bb diff --git a/src/planning/rtp/rtp/__init__.py b/src/planning/rtp/rtp/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/src/planning/rtp/rtp/rtp_node.py b/src/planning/rtp/rtp/rtp_node.py new file mode 100755 index 000000000..f7c1d75cf --- /dev/null +++ b/src/planning/rtp/rtp/rtp_node.py @@ -0,0 +1,448 @@ +''' +Package: rtp +Filename: rtp_node.py +Author: Will Heitman (w at heit.mn) + +Recursive tree planner for path generation + +For D iterations, generate N branches, where each branch is a path segment +in the map frame. Evaluate the complete cost of the path, from the previous iterations +to the current branch segment, using the latest cost map. + +When the recursion depth is hit, append the complete path to an array, along with +its cost. + +If at any point in the recursion the cost exceeds some limit, return immediately. + +At the end of recursion, select the path in the array with the least cost. + +Publish this least-cost path. + +Subscribes to: +✅ /grid/cost (OccupancyGrid) +✅ /odometry/gnss_processed (Odometry) + +Publishes: +✅ /planning/path (Path) in map frame + +Minimum update rate: 2 Hz, ideally 5 Hz +''' + +from matplotlib import pyplot as plt +from diagnostic_msgs.msg import DiagnosticStatus, KeyValue +from nav_msgs.msg import OccupancyGrid, Odometry, Path +from nova_msgs.msg import Mode +import numpy as np +import ros2_numpy as rnp +from rosgraph_msgs.msg import Clock +import rclpy +from rclpy.node import Node +from dataclasses import dataclass +import random +import time +from geometry_msgs.msg import PoseStamped, Quaternion +from carla_msgs.msg import CarlaEgoVehicleControl, CarlaSpeedometer, CarlaEgoVehicleStatus +from std_msgs.msg import String, ColorRGBA +from sensor_msgs.msg import Imu + +from visualization_msgs.msg import Marker + +from skimage.draw import line + + +from matplotlib.patches import Rectangle + +N_BRANCHES: int = 17 +STEP_LEN: float = 12.0 # meters +DEPTH: int = 3 + +# These are vdehicle constants for the GEM e6. +# The sim vehicle (Tesla Model 3) has similar constants. +WHEEL_BASE: float = 3.5 # meters +MAX_TURN_ANGLE = 0.30 # radians +COST_CUTOFF = 90 + + +@dataclass +class CostedPath: + poses = [] # pose = [x,y,heading] + cost = 0.0 + + def append(self, segment): + self.poses += segment.poses + self.cost += segment.cost + + def copy(self): + new_path = CostedPath() + new_path.poses = self.poses.copy() + new_path.cost = self.cost + return new_path + + +class RecursiveTreePlanner(Node): + def __init__(self): + super().__init__('rtp_node') + + self.speed_costmap = np.zeros((151, 151)) + + cost_map_sub = self.create_subscription( + OccupancyGrid, '/grid/cost', self.costMapCb, 1) + + speed_cost_map_sub = self.create_subscription( + OccupancyGrid, '/grid/speed_cost', self.speedCostMapCb, 1) + + self.status_pub = self.create_publisher( + DiagnosticStatus, '/node_statuses', 1) + + odom_sub = self.create_subscription( + Odometry, '/odometry/gnss_processed', self.odomCb, 1) + + current_mode_sub = self.create_subscription( + Mode, '/guardian/mode', self.currentModeCb, 1) + + clock_sub = self.create_subscription( + Clock, '/clock', self.clockCb, 1) + self.clock = Clock().clock + + self.command_pub = self.create_publisher( + CarlaEgoVehicleControl, '/control/unlimited', 1) + + self.speed_sub = self.create_subscription( + CarlaSpeedometer, '/carla/hero/speedometer', self.speedCb, 1) + + self.path_pub = self.create_publisher( + Path, '/planning/path', 1) + + self.barrier_marker_pub = self.create_publisher( + Marker, '/planning/barrier_marker', 1) + + self.ego_pose = None # [x, y, heading] + + self.speed = 0.0 + + self.current_mode = Mode.DISABLED + + def currentModeCb(self, msg: Mode): + self.current_mode = msg.mode + + def speedCostMapCb(self, msg: OccupancyGrid): + if msg.info.height == 0: + self.speed_costmap = np.asarray(msg.data, dtype=np.int8).reshape( + int(np.sqrt(len(msg.data))), -1) + + else: + self.speed_costmap = np.asarray(msg.data, dtype=np.int8).reshape( + msg.info.height, msg.info.width) + + def clockCb(self, msg: Clock): + self.clock = msg.clock + + def speedCb(self, msg: CarlaSpeedometer): + self.speed = msg.speed + + def getBarrierIndex(self, path: CostedPath, map: np.ndarray, width_meters=1.8) -> int: + """Given a path, perform a basic collision check and return the pose index + for the first pose that fails the check (such as the pose that hits a vehicle, + goes offroad, enters an intersection, etc). + + Args: + path (CostedPath): Path to be checked + map (np.ndarray): Cost map to use for the check + + Returns: + int: The index of the first pose that fails the check, where the "barrier" lies + """ + GRID_RES = 0.4 # meters per cell + + # This is the number of cells to extend to either side of the path + # It's the full width (in cells) divided by two, rounded up + REACH_CELLS = np.ceil(width_meters / GRID_RES / 2) # = 3 + + for i, pose in enumerate(path.poses): + theta = pose[2] + np.pi/2 + + ptA = np.asarray([np.cos(theta) * REACH_CELLS + pose[0], + np.sin(theta) * REACH_CELLS + pose[1]]).astype(np.int8) + ptB = np.asarray([np.cos(theta) * REACH_CELLS * -1 + pose[0], + np.sin(theta) * REACH_CELLS * -1 + pose[1]]).astype(np.int8) + + # https://scikit-image.org/docs/stable/api/skimage.draw.html#skimage.draw.line + rr, cc = line(ptA[1], ptA[0], ptB[1], ptB[0]) + + max_cost = np.max(map[rr, cc]) + + if max_cost > 90: + # map[rr, cc] = 50 + # plt.xlim(40, 110) + # plt.ylim(50, 100) + # plt.imshow(map) + # plt.show() + return i + + return len(path.poses) - 1 + + def getSegment(self, inital_pose: np.ndarray, steering_angle, segment_length: float, res: float, costmap) -> CostedPath: + end_pose = np.copy(inital_pose) + segment_poses = [] + current_length = 0.0 + total_cost = 0 + while current_length < segment_length: + end_heading = end_pose[2] + + x, y = (res * np.cos(end_heading) + end_pose[0], + res * np.sin(end_heading) + end_pose[1]) + + # Check cost at (x,y). Row-major means y is first! + if costmap.shape[0] < 1: + self.get_logger().warn("Costmap was empty") + return + cost = costmap[int(y), int(x)] + if cost > COST_CUTOFF: + return + + total_cost += cost + + segment_poses.append([ + x, y, end_heading + steering_angle + ]) + end_pose = segment_poses[-1] + current_length += res + + path = CostedPath() + path.poses = segment_poses + path.cost = total_cost + + return path + + def generatePaths(self, depth: int, path: CostedPath, steering_angle, segment_length, res, num_branches, results: list, result_costs, costmap): + # Current pose at this step is the latest pose in the current path + pose = path.poses[-1] + segment = self.getSegment( + pose, steering_angle, segment_length, res, costmap) + + if segment is None: # getSegment hit an obstacle + return + + new_path: CostedPath = path.copy() + + new_path.append(segment) + + if depth == 0: + results.append(new_path) + + if random.randint(0, 20) == 0: # Only plot 5% of results + poses_np = np.asarray(new_path.poses) + # plt.plot(poses_np[:, 0], poses_np[:, 1]) + return + + if depth == 1: + num_branches = (num_branches*2)+1 + + for angle in np.linspace(-MAX_TURN_ANGLE, MAX_TURN_ANGLE, num_branches): + self.generatePaths(depth-1, new_path, angle, segment_length, + res, num_branches, results, result_costs, costmap) + + def startGeneration(self, costmap: np.ndarray, depth=7, segment_length=9.0, branches=7): + # plt.figure(figsize=(8, 6), dpi=160) + # plt.axes().set_aspect('equal') + # print(f"Generating path with depth {depth}, seg len {segment_length}") + origin = (50., 75.) + + path = CostedPath() + path.poses = [[origin[0], origin[1], 0.0]] + path.cost = 0 + results = [] + costs = [] + + res = 1.0 + + # The below loop creates the ROOT of our recursive tree + # As a special case for the ROOT only, we multiply the number of branches + # generated in this step by a constant, allowings us to boost the resolution + # of the path when we're close to the front of the car. + # The closer we are to the front of the car, the more important a smooth path is! + + for angle in np.linspace(-MAX_TURN_ANGLE, MAX_TURN_ANGLE, branches*3): + self.generatePaths(depth-1, path, angle, segment_length, + res, branches, results, costs, costmap) + + # results = np.asarray(results) + # print(results) + # plt.imshow(costmap, origin='lower') + # plt.xlim((25,75)) + # plt.ylim((60,90)) + return results + + def publishBarrierMarker(self, pose): + marker = Marker() + marker.header.frame_id = 'base_link' + marker.header.stamp = self.clock + marker.ns = 'barrier' + marker.id = 0 + marker.type = Marker.CUBE + + marker.action = Marker.ADD + marker.pose.position.x = pose[0] * 0.4 - 20 + marker.pose.position.y = pose[1] * 0.4 - 30 + marker.pose.position.z = 1.0 + + marker.pose.orientation.z = np.sin(pose[2]/2) + marker.pose.orientation.w = np.cos(pose[2]/2) + marker.scale.x = 0.2 + marker.scale.y = 2.0 + marker.scale.z = 0.2 + + color = ColorRGBA() + color.a = 0.8 + color.r = 1.0 + marker.color = color + + self.barrier_marker_pub.publish(marker) + + def initStatusMsg(self) -> DiagnosticStatus: + status = DiagnosticStatus() + status.name = self.get_name() + + stamp = KeyValue() + stamp.key = 'stamp' + stamp.value = str(self.clock.sec+self.clock.nanosec*1e-9) + + status.values.append(stamp) + + return status + + def costMapCb(self, msg: OccupancyGrid): + start = time.time() + + status = self.initStatusMsg() + + if msg.info.height == 0 or msg.info.width == 0: + self.get_logger().warning("Incoming cost map dimensions were zero.") + return + + costmap = np.asarray(msg.data, dtype=np.int8).reshape( + msg.info.height, msg.info.width) + results = self.startGeneration( + costmap, depth=DEPTH, segment_length=STEP_LEN, branches=N_BRANCHES) + + min_cost = 100000 + best_path: CostedPath = None + + barrier_idxs = [] + + for result in results: + + # ADD BARRIER PROXIMITY COST + # (only if car is stopped) + if (self.speed < 2.0): + barrier_idx = self.getBarrierIndex( + result, self.speed_costmap) + MAX_IDX = 36 + result.cost += (MAX_IDX-barrier_idx)*50 + + barrier_idxs.append(result.cost) + if result.cost < min_cost: + min_cost = result.cost + best_path = result + + # plt.hist(barrier_idxs) + # plt.show() + + result_msg = Path() + result_msg.header.frame_id = "base_link" + result_msg.header.stamp = self.clock + + if best_path is None: + status.level = DiagnosticStatus.ERROR + status.message = "Could not find viable path. Likely too far off course." + self.get_logger().error("Could not find viable path") + self.status_pub.publish(status) + return + + barrier_idx = self.getBarrierIndex(best_path, self.speed_costmap) + barrier_pose = best_path.poses[barrier_idx] + + distance_from_barrier = np.linalg.norm( + [barrier_pose[0] * 0.4 - 20, barrier_pose[1] * 0.4 - 30]) + + self.publishBarrierMarker(barrier_pose) + + for pose in best_path.poses: + pose_msg = PoseStamped() + pose_msg.header.frame_id = "base_link" + pose_msg.header.stamp = self.clock + pose_msg.pose.position.x = pose[0] * 0.4 - 20 + pose_msg.pose.position.y = pose[1] * 0.4 - 30 + # TODO: Add heading (pose[2]?) + result_msg.poses.append(pose_msg) + + command = CarlaEgoVehicleControl() + command.steer = best_path.poses[2][2] * -2.5 # First steering value + # command.steer = -1.0 + + if command.steer > 1.0: + command.steer = 1.0 + elif command.steer < -1.0: + command.steer = -1.0 + + command.header.stamp = self.clock + + MAX_SPEED = np.min([10.0, (distance_from_barrier - 5)/2]) + target_speed = MAX_SPEED - command.steer * 3.5 # m/s, ~10mph + + pid_error = target_speed - self.speed + + if pid_error > 3.0: + command.throttle = 0.6 + command.brake = 0.0 + elif pid_error > 0.5: + command.throttle = 0.3 + command.brake = 0.0 + elif pid_error > -1.0: + # Coast if speeding by ~2 mph + command.throttle = 0.0 + command.brake = 0.0 + elif pid_error > -2.0: + # Brake slightly if speeding by ~5 mph + command.throttle = 0.0 + command.brake = 0.3 + else: + status.level = DiagnosticStatus.WARN + status.message = f"{int(abs(pid_error))} m/s over limit" + command.throttle = 0.0 + command.brake = 0.8 + + if self.current_mode == Mode.AUTO: + self.command_pub.publish(command) + + self.path_pub.publish(result_msg) + + self.status_pub.publish(status) + + # print(f"Done in {time.time() - start}!") + + def odomCb(self, msg: Odometry): + + pos = msg.pose.pose.position + heading = np.arcsin(msg.pose.pose.orientation.z) * 2 + + self.ego_pose = [pos.x, pos.y, heading] + return + + +def main(args=None): + rclpy.init(args=args) + + rtp = RecursiveTreePlanner() + + rclpy.spin(rtp) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + rtp.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/planning/rtp/setup.cfg b/src/planning/rtp/setup.cfg new file mode 100755 index 000000000..a800fc33a --- /dev/null +++ b/src/planning/rtp/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/rtp +[install] +install-scripts=$base/lib/rtp diff --git a/src/planning/rtp/setup.py b/src/planning/rtp/setup.py new file mode 100755 index 000000000..065258d97 --- /dev/null +++ b/src/planning/rtp/setup.py @@ -0,0 +1,26 @@ +from setuptools import setup + +package_name = 'rtp' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='See package.xml', + maintainer_email='See package.xml', + description='See package.xml', + license='MIT', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'rtp_node = rtp.rtp_node:main' + ], + }, +) diff --git a/src/planning/zone_lib/CMakeLists.txt b/src/planning/zone_lib/CMakeLists.txt deleted file mode 100755 index e2f29c9f7..000000000 --- a/src/planning/zone_lib/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -# Filename: CMakeLists.txt -# Author: Joshua Williams -# Email: joshmackwilliams@protonmail.com -# Copyright: 2021, Nova UTD -# License: MIT License - -# No package name is specified above since this is our standard -# CMakeLists.txt file and will be the same across multiple -# projects. To use it, just add nova_auto_package as a -# buildtool_depend in package.xml and copy this file into the root of -# your package. - -cmake_minimum_required(VERSION 3.5) -get_filename_component(directory_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) -project(${directory_name}) - -find_package(nova_auto_package REQUIRED) -nova_auto_package() \ No newline at end of file diff --git a/src/planning/zone_lib/include/zone_lib/zone.hpp b/src/planning/zone_lib/include/zone_lib/zone.hpp deleted file mode 100755 index 88cf20eb5..000000000 --- a/src/planning/zone_lib/include/zone_lib/zone.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Package: zone_lib - * Filename: zone.hpp - * Author: Egan Johnson - * Email: egan.johnson@utdallas.edu - * Copyright: 2022, Nova UTD - * License: MIT License - */ -#pragma once - -#include "nova_msgs/msg/zone.hpp" - -//libopendrive -#include "Mesh.h" -#include "Junction.h" -#include "OpenDriveMap.h" -#include "Road.h" - -#include "opendrive_utils/OpenDriveUtils.hpp" - -#include -#include -#include - -// #include "rclcpp/rclcpp.hpp" - -typedef boost::geometry::model::d2::point_xy boost_point; -typedef boost::geometry::model::polygon boost_polygon; -using PointMsg = geometry_msgs::msg::Point32; - -namespace navigator -{ - namespace zones_lib - { - using ZoneMsg = nova_msgs::msg::Zone; - using PointMsg = geometry_msgs::msg::Point32; - - boost_polygon to_boost_polygon(const ZoneMsg& zone); - boost_polygon to_boost_polygon(const odr::Mesh3D& mesh); - - ZoneMsg to_zone_msg(const boost_polygon& polygon); - ZoneMsg to_zone_msg(const odr::Mesh3D& mesh); - - //need map to look up roads - ZoneMsg to_zone_msg(std::shared_ptr junction, navigator::opendrive::types::OpenDriveMapPtr map); - - // helper function to calculate point - std::vector calculate_corner_points(std::shared_ptr lanesection, double s_val); - - class ClockwiseComparator { - public: - double mean_x, mean_y; - ClockwiseComparator(double mean_x, double mean_y) : mean_x(mean_x), mean_y(mean_y) {} - bool operator()(const PointMsg& a, const PointMsg& b) const; - }; - - - - } // namespace zones - -} // namespace navigator \ No newline at end of file diff --git a/src/planning/zone_lib/package.xml b/src/planning/zone_lib/package.xml deleted file mode 100755 index 152ff5bf1..000000000 --- a/src/planning/zone_lib/package.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - zone_lib - 0.0.0 - TODO: Package description - ejohnson - TODO: License declaration - - nova_auto_package - - boost_geometry - libopendrive - opendrive_utils - nova_msgs - rclcpp - - - ament_cmake - - diff --git a/src/planning/zone_lib/src/zone.cpp b/src/planning/zone_lib/src/zone.cpp deleted file mode 100755 index 4d259ef68..000000000 --- a/src/planning/zone_lib/src/zone.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "zone_lib/zone.hpp" -#include -#include - -using PointMsg = geometry_msgs::msg::Point32; -using ZoneMsg = nova_msgs::msg::Zone; - - -ZoneMsg navigator::zones_lib::to_zone_msg(const boost_polygon& polygon) { - ZoneMsg output; - output.max_speed = 0; - output.cost = 0; - for (auto poly_point : polygon.outer()) { - PointMsg p; - p.x = poly_point.x(); - p.y = poly_point.y(); - output.poly.points.push_back(p); - } - return output; -} - -boost_polygon navigator::zones_lib::to_boost_polygon(const odr::Mesh3D& mesh){ - boost_polygon gon; - - std::vector points; - // Split by odd/even since mesh alternates left, right, left, right, etc. - for (int parity : {0, 1}) - { - for (size_t i = parity; i < mesh.vertices.size(); i += 2) - { - auto vertex = mesh.vertices[i]; - boost::geometry::append(gon.outer(),boost_point(vertex[0], vertex[1])); - } - } - boost::geometry::correct(gon); - - return gon; -} - -ZoneMsg navigator::zones_lib::to_zone_msg(const odr::Mesh3D& mesh){ - return to_zone_msg(to_boost_polygon(mesh)); -} - -boost_polygon navigator::zones_lib::to_boost_polygon(const ZoneMsg& zone) { - boost_polygon output; - std::vector points; - for (auto p : zone.poly.points) { - boost::geometry::append(output.outer(), boost_point(p.x,p.y)); - } - //just makes sure the points are in clockwise order - boost::geometry::correct(output); - return output; -} - - -std::vector navigator::zones_lib::calculate_corner_points(std::shared_ptr lanesection, double s_val) { - - std::shared_ptr leftmost_lane; - std::shared_ptr rightmost_lane; - int left_id = -100; - int right_id = 100; - for (auto const& [lane_id, lane] : lanesection->id_to_lane) { - if (lane->type == "driving" && lane->id > left_id) { - leftmost_lane = lane; - left_id = lane->id; - } - if (lane->type == "driving" && lane->id < right_id) { - rightmost_lane = lane; - right_id = lane->id; - } - } - std::vector points; - // get t vals, then x,y - //not sure why these are null sometimes... - if (leftmost_lane != nullptr) { - double left_t = leftmost_lane->outer_border.get(s_val); - odr::Vec3D left_pt = leftmost_lane->get_surface_pt(s_val, left_t); - PointMsg left_corner; - left_corner.x = left_pt[0]; - left_corner.y = left_pt[1]; - points.push_back(left_corner); - } - if (rightmost_lane != nullptr) { - double right_t = rightmost_lane->outer_border.get(s_val); - odr::Vec3D right_pt = rightmost_lane->get_surface_pt(s_val, right_t); - PointMsg right_corner; - right_corner.x = right_pt[0]; - right_corner.y = right_pt[1]; - points.push_back(right_corner); - } - - return points; -} - - -/* - * for each incoming road into the junction (roads outside junction feeding in) - * find s value of road that connects to intersection (either 0 or s_end) - * find t values of outside farthest drivable lanes - * sample lanesection to find real coordinates for that (s,t) - * these are the two points touching the intersection on the far sides of the road - * add points to msg_points - -*/ -ZoneMsg navigator::zones_lib::to_zone_msg(std::shared_ptr junction, navigator::opendrive::types::OpenDriveMapPtr map) { - - std::vector msg_points; - for (auto const& [connection_id, junction_connection] : junction->connections) { - - // get connecting road and its lanesection (assuming only 1) - std::shared_ptr connecting_road = map->roads[junction_connection.connecting_road]; - std::shared_ptr lanesection = *(connecting_road->get_lanesections().begin()); - - // get corners for start and end of lanesection - std::vector points_start = calculate_corner_points(lanesection, 0); - std::vector points_end = calculate_corner_points(lanesection, connecting_road->length); - for (auto pt : points_start) { - msg_points.push_back(pt); - } - for (auto pt : points_end) { - msg_points.push_back(pt); - } - } - - // reorient point, sort by angle clockwise about the centroid - double mean_x = 0, mean_y = 0; - for (const PointMsg& pt : msg_points) { - mean_x += pt.x; - mean_y += pt.y; - } - ClockwiseComparator cmp(mean_x/msg_points.size(), mean_y/msg_points.size()); - std::sort(msg_points.begin(), msg_points.end(), cmp); - - ZoneMsg msg; - msg.poly.points = msg_points; - msg.max_speed = 0; - msg.cost = 0; - return msg; -} - -bool navigator::zones_lib::ClockwiseComparator::operator()(const PointMsg& a, const PointMsg& b) const { - double a_x = a.x-this->mean_x; - double a_y = a.y-this->mean_y; - double b_x = b.x-this->mean_x; - double b_y = b.y-this->mean_y; - double angle_a = std::atan2(a_y,a_x); - double angle_b = std::atan2(b_y,b_x); - //special case between quadrants 2 and 3 - //between them, the angle flips from +pi to -pi. - if (a_x <= 0 && a_y >= 0 && b_x <= 0 && b_y <= 0) { - //a in quadrant 2, b in quadrant 3, a comes before b - return true; - } - if (b_x <= 0 && b_y >= 0 && a_x <= 0 && a_y <= 0) { - //a in quadrant 3, b in quadrant 2, b comes before a - return false; - } - //otherwise, radians decrease clockwise - return angle_a > angle_b; -} diff --git a/src/planning/zone_lib/test/test_zone_lib.cpp b/src/planning/zone_lib/test/test_zone_lib.cpp deleted file mode 100755 index 6bf89313e..000000000 --- a/src/planning/zone_lib/test/test_zone_lib.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Package: zone_lib - * Filename: test_zone_lib.cpp - * Author: Jim Moore - * Email: jim3moore@gmail.com - * Copyright: 2022, Voltron UTD - * License: MIT License - */ - -#include // abs -#include // Testing framework -#include "zone_lib/zone.hpp" - -using namespace navigator::zones_lib; -using PointMsg = geometry_msgs::msg::Point32; - -class TestZoneLib : public ::testing::Test { -}; - -TEST_F(TestZoneLib, test_clockwise_comparator) { - std::vector msg_points; - PointMsg p; - p.x = 1; - p.y = 1; - msg_points.push_back(p); - p.x = -1; - p.y = 1; - msg_points.push_back(p); - p.x = -1; - p.y = -1; - msg_points.push_back(p); - p.x = 1; - p.y = -1; - msg_points.push_back(p); - - - ClockwiseComparator cmp(0,0); - std::sort(msg_points.begin(), msg_points.end(), cmp); - //points go clockwise - ASSERT_FLOAT_EQ(-1, msg_points[0].x); - ASSERT_FLOAT_EQ(1, msg_points[0].y); - - ASSERT_FLOAT_EQ(1, msg_points[1].x); - ASSERT_FLOAT_EQ(1, msg_points[1].y); - - ASSERT_FLOAT_EQ(1, msg_points[2].x); - ASSERT_FLOAT_EQ(-1, msg_points[2].y); - - ASSERT_FLOAT_EQ(-1, msg_points[3].x); - ASSERT_FLOAT_EQ(-1, msg_points[3].y); -} diff --git a/src/safety/airbags/airbags/__init__.py b/src/safety/airbags/airbags/__init__.py new file mode 100755 index 000000000..e69de29bb diff --git a/src/safety/airbags/airbags/airbag_node.py b/src/safety/airbags/airbags/airbag_node.py new file mode 100755 index 000000000..586e268f0 --- /dev/null +++ b/src/safety/airbags/airbags/airbag_node.py @@ -0,0 +1,133 @@ +''' +Package: airbags +Filename: airbag_node.py +Author: Will Heitman (w at heit.mn) + +Code to establish safety zones around the car where the speed is limited. +''' + +from matplotlib import pyplot as plt +from carla_msgs.msg import CarlaEgoVehicleControl, CarlaSpeedometer +from diagnostic_msgs.msg import DiagnosticStatus +from nav_msgs.msg import OccupancyGrid +import numpy as np +import ros2_numpy as rnp +from rosgraph_msgs.msg import Clock +import rclpy +from rclpy.node import Node +from sensor_msgs.msg import PointCloud2 +from std_msgs.msg import ColorRGBA, String +from visualization_msgs.msg import Marker +from geometry_msgs.msg import Point + +from matplotlib.patches import Rectangle + + +class AirbagNode(Node): + def __init__(self): + super().__init__('airbag_node') + + self.speed_limit = 0. # m/s + self.current_speed = 0. # m/s + + self.lidar_sub = self.create_subscription( + PointCloud2, '/lidar/filtered', self.lidarCb, 1) + + self.command_sub = self.create_subscription( + CarlaEgoVehicleControl, '/control/unlimited', self.commandCb, 1) + + self.speed_sub = self.create_subscription( + CarlaSpeedometer, '/carla/hero/speedometer', self.speedCb, 1) + + # Publishes corrected, limited commands + self.command_pub = self.create_publisher( + CarlaEgoVehicleControl, '/carla/hero/vehicle_control_cmd', 1) + + self.status_pub = self.create_publisher( + DiagnosticStatus, '/status/airbags', 1) + + self.marker_pub = self.create_publisher( + Marker, '/visuals/airbags', 1) + + self.current_airbag_pub = self.create_publisher( + String, '/planning/current_airbag', 1) + + # Clock subscription + self.clock_sub = self.create_subscription( + Clock, '/clock', self.clockCb, 10) + self._cached_clock_ = Clock() + + def speedCb(self, msg: CarlaSpeedometer): + self.current_speed = msg.speed + + def distanceToSpeedLimit(self, dist: float): + """Map distance to max speed. This should be very conservative, + limiting speed as little as possible. This means that while safety + is considered, comfort (jerky motion) is not. The motion planner + would ideally never hit this speed limit outside of an emergency. + + Args: + dist (float): Distance from closest point in front of the car (m) + + Returns: + float: speed limit (m/s) + """ + + # x = 2y+2 produces: + # 0 m/s at <1 meter + # 10 m/s (~23mph) at 21 meters + + ZERO_POINT = 2 # meters. Distances at or below will cause car to stop + + return max((dist-2)/2, 0) + + def lidarCb(self, msg: PointCloud2): + data = rnp.numpify(msg) + + # We only consider points in front of the car, not too far + # off to the side. Assume our car is ~2 meters wide. + # Filter out all other points. + data = data[data['y'] > -1.1] + data = data[data['y'] < 1.1] + data = data[data['x'] >= 0.0] + + # Of the remaining points, find the minimum x value. + if len(data) == 0: + closest_x = 999.9 + else: + closest_x = np.min(data['x']) + + self.speed_limit = self.distanceToSpeedLimit(closest_x) + + def commandCb(self, msg: CarlaEgoVehicleControl): + + if self.current_speed > self.speed_limit: + speed_over_limit = self.current_speed - self.speed_limit + self.get_logger().warning( + f"Speed is {speed_over_limit} m/s over limit!") + BRAKING_FORCE = 0.5 + msg.throttle = 0.0 + msg.brake = speed_over_limit * BRAKING_FORCE + + self.command_pub.publish(msg) + + def clockCb(self, msg: Clock): + self._cached_clock_ = msg + + +def main(args=None): + rclpy.init(args=args) + + airbag_node = AirbagNode() + + rclpy.spin(airbag_node) + + # Destroy the node explicitly + # (optional - otherwise it will be done automatically + # when the garbage collector destroys the node object) + airbag_node.destroy_node() + rclpy.shutdown() + + +if __name__ == '__main__': + main() diff --git a/src/safety/airbags/package.xml b/src/safety/airbags/package.xml new file mode 100755 index 000000000..fe06de14c --- /dev/null +++ b/src/safety/airbags/package.xml @@ -0,0 +1,19 @@ + + + + airbags + 1.0.0 + Code to establish safety zones around the car where the speed is limited. + Will Heitman + MIT + + ament_copyright + ament_flake8 + ament_pep257 + carla_msgs + python3-pytest + + + ament_python + + diff --git a/src/safety/airbags/resource/airbags b/src/safety/airbags/resource/airbags new file mode 100755 index 000000000..e69de29bb diff --git a/src/safety/airbags/setup.cfg b/src/safety/airbags/setup.cfg new file mode 100755 index 000000000..8b889fc4f --- /dev/null +++ b/src/safety/airbags/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/airbags +[install] +install-scripts=$base/lib/airbags diff --git a/src/safety/airbags/setup.py b/src/safety/airbags/setup.py new file mode 100755 index 000000000..1e6512915 --- /dev/null +++ b/src/safety/airbags/setup.py @@ -0,0 +1,26 @@ +from setuptools import setup + +package_name = 'airbags' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='See package.xml', + maintainer_email='See package.xml', + description='See package.xml', + license='MIT', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'airbag_node = airbags.airbag_node:main' + ], + }, +) diff --git a/src/safety/guardian/guardian/__init__.py b/src/safety/guardian/guardian/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/safety/guardian/guardian/guardian_node.py b/src/safety/guardian/guardian/guardian_node.py new file mode 100644 index 000000000..92393e0b7 --- /dev/null +++ b/src/safety/guardian/guardian/guardian_node.py @@ -0,0 +1,133 @@ +''' +Package: guardian +Filename: guardian_node.py +Author: Will Heitman (w at heit.mn) + +The Guardian node aggregates Navigator's diagnostic data and publishes: +- Global state description ("Stopping at intersection"), +- Mode (Enabled, Manual, Disabled), +- and global status level (OK, WARN, or ERROR). + +Subscribes to: + /node_statuses (diagnostic_msgs/DiagnosticStatus) + +Publishes to: +/status (diagnostic_msgs/DiagnosticArray) +''' + +import numpy as np +from rosgraph_msgs.msg import Clock + +from carla_msgs.msg import CarlaEgoVehicleControl +from diagnostic_msgs.msg import DiagnosticStatus, DiagnosticArray, KeyValue +from nova_msgs.msg import Mode +import rclpy +from rclpy.node import Node +from dataclasses import dataclass + + +class Sensitivity: + PREVENTS_AUTO = 0 + PREVENTS_MANUAL = 1 + PREVENTS_NOTHING = 2 + + +@dataclass +class StatusEntry: + level: DiagnosticStatus.level + message: str = "" + + +class guardian_node(Node): + joy_sub = 0.0 + command_pub = None + current_mode = Mode.DISABLED + + def __init__(self): + super().__init__('guardian_node') + + self.clock = Clock().clock + + mode_request_sub = self.create_subscription( + Mode, '/requested_mode', self.modeRequestCb, 1) + + status_sub = self.create_subscription( + DiagnosticStatus, '/node_statuses', self.statusCb, 10) + + self.status_array_pub = self.create_publisher( + DiagnosticArray, '/status', 1) + + self.current_mode_pub = self.create_publisher( + Mode, '/guardian/mode', 1) + + clock_sub = self.create_subscription(Clock, '/clock', self.clockCb, 1) + + self.watchlist = { + "rtp_node": "" + } + + status_timer = self.create_timer(0.5, self.publishStatusArray) + + def clockCb(self, msg: Clock): + self.clock = msg.clock + + def initStatusMsg(self, name: str) -> DiagnosticStatus: + status = DiagnosticStatus() + status.name = name + stamp = KeyValue() + stamp.key = 'stamp' + stamp.value = str(self.clock.sec+self.clock.nanosec*1e-9) + status.values.append(stamp) + return status + + def publishStatusArray(self): + + global_status = self.initStatusMsg('global') + array_msg = DiagnosticArray() + array_msg.header.stamp = self.clock + + for entry in self.watchlist: + status_msg = DiagnosticStatus() + status_msg.name = entry + value: StatusEntry = self.watchlist[entry] + status_msg.level = value.level + + if value.level == DiagnosticStatus.ERROR: + global_status.level = DiagnosticStatus.ERROR + global_status.message = value.message + elif value.level == DiagnosticStatus.WARN and global_status.level != DiagnosticStatus.ERROR: + global_status.level = DiagnosticStatus.WARN + global_status.message = value.message + + status_msg.message = value.message + array_msg.status.append(status_msg) + + array_msg.status.append(global_status) + + self.status_array_pub.publish(array_msg) + + def statusCb(self, msg: DiagnosticStatus): + if not msg.name in self.watchlist: + self.get_logger().warning( + f"Received status from node outside watchlist: {msg.name}") + return + self.watchlist[msg.name] = StatusEntry(msg.level, msg.message) + + # print(self.watchlist[msg.name]) + + def modeRequestCb(self, msg: Mode): + self.current_mode = msg.mode + + # Here we can choose to accept or deny the requested mode. + + mode_msg = Mode() + mode_msg.mode = self.current_mode + self.current_mode_pub.publish(mode_msg) + + +def main(args=None): + rclpy.init(args=args) + guardian = guardian_node() + rclpy.spin(guardian) + guardian_node.destroy_node() + rclpy.shutdown() diff --git a/src/safety/guardian/package.xml b/src/safety/guardian/package.xml new file mode 100755 index 000000000..f79bc72b3 --- /dev/null +++ b/src/safety/guardian/package.xml @@ -0,0 +1,16 @@ + + + + guardian + 1.0.0 + Node to aggregate diagnostic data and manage our current mode, state, and status level. + Will Heitman + MIT + + ament_lint_auto + ament_lint_common + + + ament_python + + diff --git a/src/safety/guardian/resource/guardian b/src/safety/guardian/resource/guardian new file mode 100755 index 000000000..e69de29bb diff --git a/src/safety/guardian/setup.cfg b/src/safety/guardian/setup.cfg new file mode 100755 index 000000000..b7cfcf691 --- /dev/null +++ b/src/safety/guardian/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script-dir=$base/lib/guardian +[install] +install-scripts=$base/lib/guardian diff --git a/src/safety/guardian/setup.py b/src/safety/guardian/setup.py new file mode 100755 index 000000000..8e0034a5d --- /dev/null +++ b/src/safety/guardian/setup.py @@ -0,0 +1,29 @@ +from setuptools import setup +from glob import glob +import os + +package_name = 'guardian' + +setup( + name=package_name, + version='0.0.0', + packages=[package_name], + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + (os.path.join('share', package_name), glob('launch/*.launch.py')) + ], + install_requires=['setuptools'], + zip_safe=True, + maintainer='main', + maintainer_email='will.heitman@utdallas.edu', + description='See package.xml', + license='See package.xml', + tests_require=['pytest'], + entry_points={ + 'console_scripts': [ + 'guardian_node = guardian.guardian_node:main', + ], + }, +) diff --git a/src/tools/libopendrive/CMakeLists.txt b/src/tools/libopendrive/CMakeLists.txt index 769d32bf6..8e54ab0c3 100755 --- a/src/tools/libopendrive/CMakeLists.txt +++ b/src/tools/libopendrive/CMakeLists.txt @@ -16,9 +16,7 @@ project(${directory_name}) find_package(nova_auto_package REQUIRED) -add_library(OpenDrive SHARED - src/pugixml.cpp -) + # Default to C++17 if(NOT CMAKE_CXX_STANDARD) diff --git a/src/tools/libopendrive/include/OpenDriveMap.h b/src/tools/libopendrive/include/OpenDriveMap.h index 7f49a48d4..b52f888ec 100644 --- a/src/tools/libopendrive/include/OpenDriveMap.h +++ b/src/tools/libopendrive/include/OpenDriveMap.h @@ -56,16 +56,19 @@ namespace odr std::map id_to_road; std::map id_to_junction; bgi::rtree> generate_mesh_tree(); + bgi::rtree> generate_object_tree(); std::unique_ptr road_mesh_; std::vector get_drivable_lane_polygons(float res); std::vector> get_lane_polygons(float res = 1.0, bool drivable_only = true); + std::vector> get_road_object_centers(); RoadNetworkMesh get_road_network_mesh(double eps); private: std::unique_ptr>> drivable_lane_polygons_; std::unique_ptr>> lane_polygons_; + std::vector> object_centers_; std::unique_ptr> road_polygons_; std::unique_ptr>> rtree_; }; diff --git a/src/tools/libopendrive/include/Road.h b/src/tools/libopendrive/include/Road.h index e4e65fb61..0f72dccde 100644 --- a/src/tools/libopendrive/include/Road.h +++ b/src/tools/libopendrive/include/Road.h @@ -5,6 +5,7 @@ #include "Mesh.h" #include "RefLine.h" #include "RoadObject.h" +#include "RoadSignal.h" #include "XmlNode.h" #include @@ -15,117 +16,119 @@ namespace odr { -struct Lane; -struct RoadMark; + struct Lane; + struct RoadMark; -struct Crossfall : public CubicSpline -{ - enum Side + struct Crossfall : public CubicSpline { - Side_Both, - Side_Left, - Side_Right - }; + enum Side + { + Side_Both, + Side_Left, + Side_Right + }; - Crossfall() = default; + Crossfall() = default; - double get_crossfall(const double s, const bool on_left_side) const; + double get_crossfall(const double s, const bool on_left_side) const; - std::map sides; -}; - -struct RoadLink : public XmlNode -{ - enum ContactPoint - { - ContactPoint_None, - ContactPoint_Start, - ContactPoint_End + std::map sides; }; - enum Type + struct RoadLink : public XmlNode { - Type_None, - Type_Road, - Type_Junction + enum ContactPoint + { + ContactPoint_None, + ContactPoint_Start, + ContactPoint_End + }; + + enum Type + { + Type_None, + Type_Road, + Type_Junction + }; + + RoadLink() = default; + RoadLink(std::string id, Type type, ContactPoint contact_point); + + std::string id = ""; + Type type = Type_None; + ContactPoint contact_point = ContactPoint_None; }; - RoadLink() = default; - RoadLink(std::string id, Type type, ContactPoint contact_point); - - std::string id = ""; - Type type = Type_None; - ContactPoint contact_point = ContactPoint_None; -}; - -struct RoadNeighbor : public XmlNode -{ - RoadNeighbor(std::string id, std::string side, std::string direction); + struct RoadNeighbor : public XmlNode + { + RoadNeighbor(std::string id, std::string side, std::string direction); - std::string id = ""; - std::string side = ""; - std::string direction = ""; -}; + std::string id = ""; + std::string side = ""; + std::string direction = ""; + }; -struct SpeedRecord : public XmlNode -{ - SpeedRecord(std::string max, std::string unit); + struct SpeedRecord : public XmlNode + { + SpeedRecord(std::string max, std::string unit); - std::string max = ""; - std::string unit = ""; -}; + std::string max = ""; + std::string unit = ""; + }; -class Road : public XmlNode -{ -public: - Road(std::string id, double length, std::string junction, std::string name); + class Road : public XmlNode + { + public: + Road(std::string id, double length, std::string junction, std::string name); - std::vector get_lanesections() const; - std::vector get_road_objects() const; + std::vector get_lanesections() const; + std::vector get_road_objects() const; + std::vector get_signals() const; - double get_lanesection_s0(const double s) const; - LaneSection get_lanesection(const double s) const; + double get_lanesection_s0(const double s) const; + LaneSection get_lanesection(const double s) const; - double get_lanesection_end(const LaneSection& lanesection) const; - double get_lanesection_end(const double lanesection_s0) const; - double get_lanesection_length(const LaneSection& lanesection) const; - double get_lanesection_length(const double lanesection_s0) const; + double get_lanesection_end(const LaneSection &lanesection) const; + double get_lanesection_end(const double lanesection_s0) const; + double get_lanesection_length(const LaneSection &lanesection) const; + double get_lanesection_length(const double lanesection_s0) const; - Vec3D get_xyz(const double s, const double t, const double h, Vec3D* e_s = nullptr, Vec3D* e_t = nullptr, Vec3D* e_h = nullptr) const; - Vec3D get_surface_pt(double s, const double t, Vec3D* vn = nullptr) const; + Vec3D get_xyz(const double s, const double t, const double h, Vec3D *e_s = nullptr, Vec3D *e_t = nullptr, Vec3D *e_h = nullptr) const; + Vec3D get_surface_pt(double s, const double t, Vec3D *vn = nullptr) const; - Line3D get_lane_border_line(const Lane& lane, const double s_start, const double s_end, const double eps, const bool outer = true) const; - Line3D get_lane_border_line(const Lane& lane, const double eps, const bool outer = true) const; + Line3D get_lane_border_line(const Lane &lane, const double s_start, const double s_end, const double eps, const bool outer = true) const; + Line3D get_lane_border_line(const Lane &lane, const double eps, const bool outer = true) const; - Mesh3D get_lane_mesh( - const Lane& lane, const double s_start, const double s_end, const double eps, std::vector* outline_indices = nullptr) const; - Mesh3D get_lane_mesh(const Lane& lane, const double eps, std::vector* outline_indices = nullptr) const; + Mesh3D get_lane_mesh( + const Lane &lane, const double s_start, const double s_end, const double eps, std::vector *outline_indices = nullptr) const; + Mesh3D get_lane_mesh(const Lane &lane, const double eps, std::vector *outline_indices = nullptr) const; - Mesh3D get_roadmark_mesh(const Lane& lane, const RoadMark& roadmark, const double eps) const; - Mesh3D get_road_object_mesh(const RoadObject& road_object, const double eps) const; + Mesh3D get_roadmark_mesh(const Lane &lane, const RoadMark &roadmark, const double eps) const; + Mesh3D get_road_object_mesh(const RoadObject &road_object, const double eps) const; - std::set - approximate_lane_border_linear(const Lane& lane, const double s_start, const double s_end, const double eps, const bool outer = true) const; - std::set approximate_lane_border_linear(const Lane& lane, const double eps, const bool outer = true) const; + std::set + approximate_lane_border_linear(const Lane &lane, const double s_start, const double s_end, const double eps, const bool outer = true) const; + std::set approximate_lane_border_linear(const Lane &lane, const double eps, const bool outer = true) const; - double length = 0; - std::string id = ""; - std::string junction = ""; - std::string name = ""; + double length = 0; + std::string id = ""; + std::string junction = ""; + std::string name = ""; - RoadLink predecessor; - RoadLink successor; - std::vector neighbors; + RoadLink predecessor; + RoadLink successor; + std::vector neighbors; - CubicSpline lane_offset; - CubicSpline superelevation; - Crossfall crossfall; - RefLine ref_line; + CubicSpline lane_offset; + CubicSpline superelevation; + Crossfall crossfall; + RefLine ref_line; - std::map s_to_lanesection; - std::map s_to_type; - std::map s_to_speed; - std::map id_to_object; -}; + std::map s_to_lanesection; + std::map s_to_type; + std::map s_to_speed; + std::map id_to_object; + std::map id_to_signal; + }; } // namespace odr diff --git a/src/tools/libopendrive/include/RoadSignal.h b/src/tools/libopendrive/include/RoadSignal.h new file mode 100644 index 000000000..192c6bee4 --- /dev/null +++ b/src/tools/libopendrive/include/RoadSignal.h @@ -0,0 +1,52 @@ +#pragma once +#include "Math.hpp" +#include "Mesh.h" +#include "XmlNode.h" + +#include +#include + +namespace odr +{ + + struct RoadSignal : public XmlNode + { + RoadSignal(std::string road_id, + std::string id, + double s, + double t, + double z0, + bool dynamic, + double width, + double height, + double hdg, + double pitch, + double roll, + std::string type, + std::string subtype, + std::string name, + std::string orientation, + std::string country); + + static Mesh3D get_cylinder(const double eps, const double radius, const double height); + static Mesh3D get_box(const double width, const double length, const double height); + + std::string road_id; + std::string id; + double s; + double t; + double z0; + bool dynamic; + double width; + double height; + double hdg; + double pitch; + double roll; + std::string type; + std::string subtype; + std::string name; + std::string orientation; + std::string country; + }; + +} // namespace odr \ No newline at end of file diff --git a/src/tools/libopendrive/src/OpenDriveMap.cpp b/src/tools/libopendrive/src/OpenDriveMap.cpp index 8aa9dbefa..1d5c21494 100644 --- a/src/tools/libopendrive/src/OpenDriveMap.cpp +++ b/src/tools/libopendrive/src/OpenDriveMap.cpp @@ -13,6 +13,7 @@ #include "Road.h" #include "RoadMark.h" #include "RoadObject.h" +#include "RoadSignal.h" #include "Utils.hpp" #include @@ -550,6 +551,38 @@ namespace odr road_object.outline.push_back(road_object_corner_road); } } + + for (pugi::xml_node signal_node : road_node.child("signals").children("signal")) + { + std::string road_signal_id = signal_node.attribute("id").as_string(""); + CHECK_AND_REPAIR(road.id_to_signal.find(road_signal_id) == road.id_to_signal.end(), + (std::string("signal::id already exists - ") + road_signal_id).c_str(), + road_signal_id = road_signal_id + std::string("_dup")); + + RoadSignal &road_signal = road.id_to_signal + .insert({road_signal_id, + RoadSignal(road_id, + road_signal_id, + signal_node.attribute("s").as_double(0), + signal_node.attribute("t").as_double(0), + signal_node.attribute("zOffset").as_double(0), + signal_node.attribute("dynamic").as_bool(0), + signal_node.attribute("width").as_double(0), + signal_node.attribute("height").as_double(0), + signal_node.attribute("hdg").as_double(0), + signal_node.attribute("pitch").as_double(0), + signal_node.attribute("roll").as_double(0), + signal_node.attribute("type").as_string(""), + signal_node.attribute("subtype").as_string(""), + signal_node.attribute("name").as_string(""), + signal_node.attribute("orientation").as_string(""), + signal_node.attribute("country").as_string(""))}) + .first->second; + road_signal.xml_node = signal_node; + + CHECK_AND_REPAIR(road_signal.s >= 0, "signal::s < 0", road_signal.s = 0); + CHECK_AND_REPAIR(road_signal.width >= 0, "signal::width < 0", road_signal.width = 0); + } } } } @@ -683,7 +716,7 @@ namespace odr std::cout << "Start of generate_mesh_tree()" << std::endl; bgi::rtree> rtree; - std::vector> polys = get_lane_polygons(1.0); + std::vector> polys = get_lane_polygons(1.0, false); std::printf("get_road_polygons returned %i shapes\n", polys.size()); // fill the spatial index @@ -699,6 +732,59 @@ namespace odr return rtree; } + std::vector> OpenDriveMap::get_road_object_centers() + { + if (object_centers_.size() > 0) + return object_centers_; // No need to calculate twice. + + for (Road road : get_roads()) + { + for (RoadObject obj : road.get_road_objects()) + { + float s = obj.s0; + float t = obj.t0; + odr::Vec3D xyz = road.get_surface_pt(s, t); + point pt = point(xyz[0], xyz[1]); + object_centers_.push_back(std::make_pair(obj, pt)); + } + for (RoadSignal sig : road.get_signals()) + { + RoadObject obj(road.id, sig.id, sig.s, sig.t, sig.z0, + 0.0, 0.0, sig.width, 0.1, sig.height, sig.hdg, sig.pitch, + sig.roll, sig.type, sig.name, sig.orientation); + float s = obj.s0; + float t = obj.t0; + odr::Vec3D xyz = road.get_surface_pt(s, t); + point pt = point(xyz[0], xyz[1]); + object_centers_.push_back(std::make_pair(obj, pt)); + } + } + return object_centers_; + } + + bgi::rtree> OpenDriveMap::generate_object_tree() + { + std::cout << "Start of generate_object_tree()" << std::endl; + bgi::rtree> rtree; + + if (object_centers_.size() < 1) + get_road_object_centers(); + + std::printf("map has %i objects\n", object_centers_.size()); + + // fill the spatial index + for (unsigned i = 0; i < object_centers_.size(); ++i) + { + // calculate polygon bounding box + box b = bg::return_envelope(object_centers_[i].second); + // insert new value + rtree.insert(std::make_pair(b, i)); + // std::printf("Inserting box (%f, %f)-(%f,%f)\n", b.min_corner().get<0>(), b.min_corner().get<1>(), b.max_corner().get<0>(), b.max_corner().get<1>()); + } + // std::printf("End of generate_mesh_tree(), tree has %i shapes\n", rtree.size()); + return rtree; + } + RoadNetworkMesh OpenDriveMap::get_road_network_mesh(double eps) { std::cout << "Start of get_road_network_mesh()" << std::endl; diff --git a/src/tools/libopendrive/src/Road.cpp b/src/tools/libopendrive/src/Road.cpp index 378307414..c499fdfab 100644 --- a/src/tools/libopendrive/src/Road.cpp +++ b/src/tools/libopendrive/src/Road.cpp @@ -55,6 +55,7 @@ namespace odr std::vector Road::get_lanesections() const { return get_map_values(this->s_to_lanesection); } std::vector Road::get_road_objects() const { return get_map_values(this->id_to_object); } + std::vector Road::get_signals() const { return get_map_values(this->id_to_signal); } Road::Road(std::string id, double length, std::string junction, std::string name) : length(length), id(id), junction(junction), name(name), ref_line(id, length) { diff --git a/src/tools/libopendrive/src/RoadSignal.cpp b/src/tools/libopendrive/src/RoadSignal.cpp new file mode 100644 index 000000000..7261b0f46 --- /dev/null +++ b/src/tools/libopendrive/src/RoadSignal.cpp @@ -0,0 +1,82 @@ +#include "RoadSignal.h" + +#include +#include +#include +#include + +namespace odr +{ + RoadSignal::RoadSignal(std::string road_id, + std::string id, + double s, + double t, + double z0, + bool dynamic, + double width, + double height, + double hdg, + double pitch, + double roll, + std::string type, + std::string subtype, + std::string name, + std::string orientation, + std::string country) : road_id(road_id), + id(id), type(type), subtype(subtype), name(name), orientation(orientation), s(s), t(t), z0(z0), width(width), + height(height), hdg(hdg), pitch(pitch), roll(roll), country(country) + { + } + + Mesh3D RoadSignal::get_cylinder(const double eps, const double radius, const double height) + { + Mesh3D cylinder_mesh; + cylinder_mesh.vertices.push_back({0, 0, 0}); + cylinder_mesh.vertices.push_back({0, 0, height}); + + const double eps_adj = 0.5 * eps; // reduce eps a bit, cylinders more subsceptible to low resolution + const double eps_angle = + (radius <= eps_adj) ? M_PI / 6 : std::acos((radius * radius - 4 * radius * eps_adj + 2 * eps_adj * eps_adj) / (radius * radius)); + + std::vector angles; + for (double alpha = 0; alpha < 2 * M_PI; alpha += eps_angle) + angles.push_back(alpha); + angles.push_back(2 * M_PI); + + for (const double &alpha : angles) + { + const Vec3D circle_pt_bottom = {radius * std::cos(alpha), radius * std::sin(alpha), 0}; + const Vec3D circle_pt_top = {radius * std::cos(alpha), radius * std::sin(alpha), height}; + cylinder_mesh.vertices.push_back(circle_pt_bottom); + cylinder_mesh.vertices.push_back(circle_pt_top); + + if (cylinder_mesh.vertices.size() > 5) + { + const std::size_t cur_idx = cylinder_mesh.vertices.size() - 1; + std::array top_bottom_idx_patch = {0, cur_idx - 1, cur_idx - 3, 1, cur_idx - 2, cur_idx}; + cylinder_mesh.indices.insert(cylinder_mesh.indices.end(), top_bottom_idx_patch.begin(), top_bottom_idx_patch.end()); + std::array wall_idx_patch = {cur_idx, cur_idx - 2, cur_idx - 3, cur_idx, cur_idx - 3, cur_idx - 1}; + cylinder_mesh.indices.insert(cylinder_mesh.indices.end(), wall_idx_patch.begin(), wall_idx_patch.end()); + } + } + + return cylinder_mesh; + } + + Mesh3D RoadSignal::get_box(const double w, const double l, const double h) + { + Mesh3D box_mesh; + box_mesh.vertices = {Vec3D{l / 2, w / 2, 0}, + Vec3D{-l / 2, w / 2, 0}, + Vec3D{-l / 2, -w / 2, 0}, + Vec3D{l / 2, -w / 2, 0}, + Vec3D{l / 2, w / 2, h}, + Vec3D{-l / 2, w / 2, h}, + Vec3D{-l / 2, -w / 2, h}, + Vec3D{l / 2, -w / 2, h}}; + box_mesh.indices = {0, 3, 1, 3, 2, 1, 4, 5, 7, 7, 5, 6, 7, 6, 3, 3, 6, 2, 5, 4, 1, 1, 4, 0, 0, 4, 7, 7, 3, 0, 1, 6, 5, 1, 2, 6}; + + return box_mesh; + } + +} // namespace odr diff --git a/src/tools/nova_dash/client/README.md b/src/tools/nova_dash/client/README.md deleted file mode 100755 index f6ba2165e..000000000 --- a/src/tools/nova_dash/client/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Nova Client Dashboard -This is Nova's Client Dashboard environment. - -# To use: -- Source dependencies using `npm install` -- Replace `/node_modules/react-scripts/config/webpack.config.dev.js` with the `webpack.config.dev.js` in the home folder -- Run the server (server.js) to start the websocket handler -- Run `npm start` to start the react handler \ No newline at end of file diff --git a/src/tools/nova_dash/client/package-lock.json b/src/tools/nova_dash/client/package-lock.json deleted file mode 100755 index a967d6fb8..000000000 --- a/src/tools/nova_dash/client/package-lock.json +++ /dev/null @@ -1,37768 +0,0 @@ -{ - "name": "nova-dash-client", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "nova-dash-client", - "version": "1.0.0", - "dependencies": { - "react": "16.8.0", - "react-burger-menu": "^3.0.6", - "react-dom": "16.8.0", - "react-router-dom": "^6.2.2", - "react-scripts": "2.0.3", - "regl-worldview": "latest", - "websocket": "^1.0.34" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.0.tgz", - "integrity": "sha512-9EWmD0cQAbcXSc+31RIoYgEHx3KQ2CCSMDBhnXrShWvo45TMw+3/55KVxlhkG53kw9tl87DqINgHDgFVhZJV/Q==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.0.0", - "@babel/helpers": "^7.1.0", - "@babel/parser": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0", - "convert-source-map": "^1.1.0", - "debug": "^3.1.0", - "json5": "^0.5.0", - "lodash": "^4.17.10", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", - "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", - "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-map": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.16.7.tgz", - "integrity": "sha512-SoIOh18NdeBBQjiLF1H32jpDLkApTbUWwEXmqaxn1KEm7aqry4reaghMdCdkbdloVmMwUxM/uCcTmHWj9zJbxQ==", - "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dependencies": { - "@babel/types": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", - "dependencies": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz", - "integrity": "sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.0.0.tgz", - "integrity": "sha512-WhXUNb4It5a19RsgKKbQPrjmy4yWOY1KynpEbNw7bnd1QTcrT/EIl3MJvnGgpgvrKyKbqX7nUNOJfkpLOnoDKA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.16.7.tgz", - "integrity": "sha512-lF+cfsyTgwWkcw715J88JhMYJ5GpysYNLhLP1PkvkhTRN7B3e74R/1KsDxFxhRpSn0UUD3IWM4GvdBR2PEbbQQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", - "integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.7.tgz", - "integrity": "sha512-oe5VuWs7J9ilH3BCCApGoYjHoSO48vkjX2CbA5bFVhIuO2HKxA3vyF7rleA4o6/4rTDbk6r8hBW7Ul8E+UZrpA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.7.tgz", - "integrity": "sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "dependencies": { - "regenerator-transform": "^0.14.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.1.0.tgz", - "integrity": "sha512-WFLMgzu5DLQEah0lKTJzYb14vd6UiES7PTnXcvrPZ1VrwFeJ+mTbvr65fFAsXYMt2bIoOoC0jk76zY1S7HZjUg==", - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "resolve": "^1.8.1", - "semver": "^5.5.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@babel/traverse/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@csstools/convert-colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", - "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/@mapbox/tiny-sdf": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.4.tgz", - "integrity": "sha512-CBtL2rhZiYmdIryksp0zh4Mmx54iClYfNb0mpYeHrZnq4z84lVjre7LBWGPEjWspEn6AiF0lxC1HaZDye89m3g==" - }, - "node_modules/@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@svgr/core": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-2.4.1.tgz", - "integrity": "sha512-2i1cUbjpKt1KcIP05e10vkmu9Aedp32EFqVcSQ08onbB8lVxJqMPci3Hr54aI14S9cLg4JdcpO0D35HHUtT8oQ==", - "dependencies": { - "camelcase": "^5.0.0", - "cosmiconfig": "^5.0.6", - "h2x-core": "^1.1.0", - "h2x-plugin-jsx": "^1.1.0", - "merge-deep": "^3.0.2", - "prettier": "^1.14.2", - "svgo": "^1.0.5" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@svgr/webpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-2.4.1.tgz", - "integrity": "sha512-sMHYq0zbMtSHcc9kVfkYI2zrl88u4mKGyQLgKt7r+ul5nITcncm/EPBhzEUrJY5izdlaU6EvyH8zOhZnfaSmOA==", - "dependencies": { - "@babel/core": "^7.0.1", - "@babel/plugin-transform-react-constant-elements": "^7.0.0", - "@babel/preset-env": "^7.0.0", - "@babel/preset-react": "^7.0.0", - "@svgr/core": "^2.4.1", - "loader-utils": "^1.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" - }, - "node_modules/@types/tapable": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.2.tgz", - "integrity": "sha512-42zEJkBpNfMEAvWR5WlwtTH22oDzcMjFsL9gDGExwF8X8WvAiw7Vwop7hPw03QT8TKfec83LwbHj6SvpqM4ELQ==" - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.6.tgz", - "integrity": "sha512-8nkZS48EVsMUU0v6F1LCIOw4RYWLm2plMtbhFTjNgeXmsTNLuU3xTRtnljt9BFQB+iPbLRobkNrCWftWnNC7wQ==", - "dependencies": { - "@webassemblyjs/helper-module-context": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/wast-parser": "1.7.6", - "mamacro": "^0.0.3" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz", - "integrity": "sha512-VBOZvaOyBSkPZdIt5VBMg3vPWxouuM13dPXGWI1cBh3oFLNcFJ8s9YA7S9l4mPI7+Q950QqOmqj06oa83hNWBA==" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz", - "integrity": "sha512-SCzhcQWHXfrfMSKcj8zHg1/kL9kb3aa5TN4plc/EREOs5Xop0ci5bdVBApbk2yfVi8aL+Ly4Qpp3/TRAUInjrg==" - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz", - "integrity": "sha512-1/gW5NaGsEOZ02fjnFiU8/OEEXU1uVbv2um0pQ9YVL3IHSkyk6xOwokzyqqO1qDZQUAllb+V8irtClPWntbVqw==" - }, - "node_modules/@webassemblyjs/helper-code-frame": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz", - "integrity": "sha512-+suMJOkSn9+vEvDvgyWyrJo5vJsWSDXZmJAjtoUq4zS4eqHyXImpktvHOZwXp1XQjO5H+YQwsBgqTQEc0J/5zg==", - "dependencies": { - "@webassemblyjs/wast-printer": "1.7.6" - } - }, - "node_modules/@webassemblyjs/helper-fsm": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz", - "integrity": "sha512-HCS6KN3wgxUihGBW7WFzEC/o8Eyvk0d56uazusnxXthDPnkWiMv+kGi9xXswL2cvfYfeK5yiM17z2K5BVlwypw==" - }, - "node_modules/@webassemblyjs/helper-module-context": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz", - "integrity": "sha512-e8/6GbY7OjLM+6OsN7f2krC2qYVNaSr0B0oe4lWdmq5sL++8dYDD1TFbD1TdAdWMRTYNr/Qq7ovXWzia2EbSjw==", - "dependencies": { - "mamacro": "^0.0.3" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz", - "integrity": "sha512-PzYFCb7RjjSdAOljyvLWVqd6adAOabJW+8yRT+NWhXuf1nNZWH+igFZCUK9k7Cx7CsBbzIfXjJc7u56zZgFj9Q==" - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz", - "integrity": "sha512-3GS628ppDPSuwcYlQ7cDCGr4W2n9c4hLzvnRKeuz+lGsJSmc/ADVoYpm1ts2vlB1tGHkjtQMni+yu8mHoMlKlA==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz", - "integrity": "sha512-V4cIp0ruyw+hawUHwQLn6o2mFEw4t50tk530oKsYXQhEzKR+xNGDxs/SFFuyTO7X3NzEu4usA3w5jzhl2RYyzQ==", - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.6.tgz", - "integrity": "sha512-ojdlG8WpM394lBow4ncTGJoIVZ4aAtNOWHhfAM7m7zprmkVcKK+2kK5YJ9Bmj6/ketTtOn7wGSHCtMt+LzqgYQ==", - "dependencies": { - "@xtuc/long": "4.2.1" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.6.tgz", - "integrity": "sha512-oId+tLxQ+AeDC34ELRYNSqJRaScB0TClUU6KQfpB8rNT6oelYlz8axsPhf6yPTg7PBJ/Z5WcXmUYiHEWgbbHJw==" - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz", - "integrity": "sha512-pTNjLO3o41v/Vz9VFLl+I3YLImpCSpodFW77pNoH4agn5I6GgSxXHXtvWDTvYJFty0jSeXZWLEmbaSIRUDlekg==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/helper-wasm-section": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6", - "@webassemblyjs/wasm-opt": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6", - "@webassemblyjs/wast-printer": "1.7.6" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz", - "integrity": "sha512-mQvFJVumtmRKEUXMohwn8nSrtjJJl6oXwF3FotC5t6e2hlKMh8sIaW03Sck2MDzw9xPogZD7tdP5kjPlbH9EcQ==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/ieee754": "1.7.6", - "@webassemblyjs/leb128": "1.7.6", - "@webassemblyjs/utf8": "1.7.6" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz", - "integrity": "sha512-go44K90fSIsDwRgtHhX14VtbdDPdK2sZQtZqUcMRvTojdozj5tLI0VVJAzLCfz51NOkFXezPeVTAYFqrZ6rI8Q==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz", - "integrity": "sha512-t1T6TfwNY85pDA/HWPA8kB9xA4sp9ajlRg5W7EKikqrynTyFo+/qDzIpvdkOkOGjlS6d4n4SX59SPuIayR22Yg==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-api-error": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/ieee754": "1.7.6", - "@webassemblyjs/leb128": "1.7.6", - "@webassemblyjs/utf8": "1.7.6" - } - }, - "node_modules/@webassemblyjs/wast-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz", - "integrity": "sha512-1MaWTErN0ziOsNUlLdvwS+NS1QWuI/kgJaAGAMHX8+fMJFgOJDmN/xsG4h/A1Gtf/tz5VyXQciaqHZqp2q0vfg==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/floating-point-hex-parser": "1.7.6", - "@webassemblyjs/helper-api-error": "1.7.6", - "@webassemblyjs/helper-code-frame": "1.7.6", - "@webassemblyjs/helper-fsm": "1.7.6", - "@xtuc/long": "4.2.1", - "mamacro": "^0.0.3" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz", - "integrity": "sha512-vHdHSK1tOetvDcl1IV1OdDeGNe/NDDQ+KzuZHMtqTVP1xO/tZ/IKNpj5BaGk1OYFdsDWQqb31PIwdEyPntOWRQ==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/wast-parser": "1.7.6", - "@xtuc/long": "4.2.1" - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "node_modules/@xtuc/long": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", - "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==" - }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", - "dependencies": { - "acorn": "^5.0.0" - } - }, - "node_modules/acorn-dynamic-import/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/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==", - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/address": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", - "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==", - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agent-base/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "peerDependencies": { - "ajv": ">=5.0.0" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "optional": true, - "engines": { - "node": ">=0.4.2" - } - }, - "node_modules/ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/anymatch/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/anymatch/node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", - "dependencies": { - "default-require-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/aria-query": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", - "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", - "dependencies": { - "ast-types-flow": "0.0.7", - "commander": "^2.11.0" - } - }, - "node_modules/arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dependencies": { - "arr-flatten": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" - }, - "node_modules/array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" - }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" - }, - "node_modules/array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" - }, - "node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "dependencies": { - "object-assign": "^4.1.1", - "util": "0.10.3" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/assert/node_modules/inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - }, - "node_modules/assert/node_modules/util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dependencies": { - "inherits": "2.0.1" - } - }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ast-transform": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", - "integrity": "sha1-dJRAWIh9goPhidlUYAlHvJj+AGI=", - "dependencies": { - "escodegen": "~1.2.0", - "esprima": "~1.0.4", - "through": "~2.3.4" - } - }, - "node_modules/ast-transform/node_modules/escodegen": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", - "integrity": "sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E=", - "dependencies": { - "esprima": "~1.0.4", - "estraverse": "~1.5.0", - "esutils": "~1.0.0" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=0.4.0" - }, - "optionalDependencies": { - "source-map": "~0.1.30" - } - }, - "node_modules/ast-transform/node_modules/esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ast-transform/node_modules/estraverse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", - "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ast-transform/node_modules/esutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", - "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ast-transform/node_modules/source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "optional": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/ast-types": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", - "integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=" - }, - "node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" - }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/autoprefixer": { - "version": "9.8.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", - "dependencies": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "picocolors": "^0.2.1", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - }, - "node_modules/autoprefixer/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/autoprefixer/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/autoprefixer/node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/autoprefixer/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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=", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "node_modules/axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" - }, - "node_modules/babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dependencies": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "node_modules/babel-code-frame/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "node_modules/babel-code-frame/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-code-frame/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/babel-core": { - "version": "7.0.0-bridge.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-eslint": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-9.0.0.tgz", - "integrity": "sha512-itv1MwE3TMbY0QtNfeL7wzak1mV47Uy+n6HtSOO4Xd7rvmO+tsGQSgyOEEgo6Y2vHZKZphaoelNeSVj4vkLA1g==", - "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/babel-extract-comments": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", - "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", - "dependencies": { - "babylon": "^6.18.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dependencies": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - } - }, - "node_modules/babel-generator/node_modules/jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "dependencies": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "node_modules/babel-jest": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", - "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", - "dependencies": { - "babel-plugin-istanbul": "^4.1.6", - "babel-preset-jest": "^23.2.0" - }, - "peerDependencies": { - "babel-core": "^6.0.0 || ^7.0.0-0" - } - }, - "node_modules/babel-loader": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.4.tgz", - "integrity": "sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==", - "dependencies": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0" - }, - "engines": { - "node": ">= 6.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dependencies": { - "babel-runtime": "^6.22.0" - } - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", - "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", - "dependencies": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", - "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=" - }, - "node_modules/babel-plugin-macros": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.4.2.tgz", - "integrity": "sha512-NBVpEWN4OQ/bHnu1fyDaAaTPAjnhXCEPqr1RwqxrU7b6tZ2hypp+zX4hlNfmVGfClD5c3Sl6Hfj5TJNF5VG5aA==", - "dependencies": { - "cosmiconfig": "^5.0.5", - "resolve": "^1.8.1" - } - }, - "node_modules/babel-plugin-named-asset-import": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.2.3.tgz", - "integrity": "sha512-9mx2Z9M4EGbutvXxoLV7aUBCY6ps3sqLFl094FeA2tFQzQffIh0XSsmwwQRxiSfpg3rnb5x/o46qRLxS/OzFTg==", - "peerDependencies": { - "@babel/core": "^7.1.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", - "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" - }, - "node_modules/babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", - "dependencies": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - } - }, - "node_modules/babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.18.tgz", - "integrity": "sha512-azed2nHo8vmOy7EY26KH+om5oOcWRs0r1U8wOmhwta+SBMMnmJ4H6yaBZRCcHBtMeWp9AVhvBTL/lpR1kEx+Xw==" - }, - "node_modules/babel-preset-jest": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", - "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", - "dependencies": { - "babel-plugin-jest-hoist": "^23.2.0", - "babel-plugin-syntax-object-rest-spread": "^6.13.0" - } - }, - "node_modules/babel-preset-react-app": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-5.0.4.tgz", - "integrity": "sha512-NQ344N1BXY4ur8c7iRqj1JQvcI6tiLbNB8W2z0Vanmc6xld+EG9CYk9cfIFTPgk5RCkughimt+0uw2nd2CyevQ==", - "dependencies": { - "@babel/core": "7.1.0", - "@babel/plugin-proposal-class-properties": "7.1.0", - "@babel/plugin-proposal-object-rest-spread": "7.0.0", - "@babel/plugin-syntax-dynamic-import": "7.0.0", - "@babel/plugin-transform-classes": "7.1.0", - "@babel/plugin-transform-destructuring": "7.0.0", - "@babel/plugin-transform-flow-strip-types": "7.0.0", - "@babel/plugin-transform-react-constant-elements": "7.0.0", - "@babel/plugin-transform-react-display-name": "7.0.0", - "@babel/plugin-transform-runtime": "7.1.0", - "@babel/preset-env": "7.1.0", - "@babel/preset-react": "7.0.0", - "@babel/runtime": "7.0.0", - "babel-loader": "8.0.4", - "babel-plugin-dynamic-import-node": "2.2.0", - "babel-plugin-macros": "2.4.2", - "babel-plugin-transform-react-remove-prop-types": "0.4.18" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz", - "integrity": "sha512-/PCJWN+CKt5v1xcGn4vnuu13QDoV+P7NcICP44BoonAJoPSGwVkgrXihFIQGiEjjPlUDBIw1cM7wYFLARS2/hw==", - "dependencies": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/plugin-syntax-class-properties": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz", - "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.0.0.tgz", - "integrity": "sha512-Gt9xNyRrCHCiyX/ZxDGOcBnlJl0I3IWicpZRC4CdC0P5a/I07Ya2OAMEBU+J7GmRFVmIetqEYRko6QYRuKOESw==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/plugin-transform-classes": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz", - "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.1.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "globals": "^11.1.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/plugin-transform-destructuring": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0.tgz", - "integrity": "sha512-Fr2GtF8YJSXGTyFPakPFB4ODaEKGU04bPsAllAIabwoXdFrPxL0LVXQX5dQWoxOjjgozarJcC9eWGsj0fD6Zsg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/plugin-transform-react-constant-elements": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.0.0.tgz", - "integrity": "sha512-z8yrW4KCVcqPYr0r9dHXe7fu3daLzn0r6TQEFoGbXahdrzEwT1d1ux+/EnFcqIHv9uPilUlnRnPIUf7GMO0ehg==", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.0.0.tgz", - "integrity": "sha512-BX8xKuQTO0HzINxT6j/GiCwoJB0AOMs0HmLbEnAvcte8U8rSkNa/eSCAY+l1OA4JnCVq2jw2p6U8QQryy2fTPg==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/preset-env": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz", - "integrity": "sha512-ZLVSynfAoDHB/34A17/JCZbyrzbQj59QC1Anyueb4Bwjh373nVPq5/HMph0z+tCmcDjXDe+DlKQq9ywQuvWrQg==", - "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.1.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", - "@babel/plugin-syntax-async-generators": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-async-to-generator": "^7.1.0", - "@babel/plugin-transform-block-scoped-functions": "^7.0.0", - "@babel/plugin-transform-block-scoping": "^7.0.0", - "@babel/plugin-transform-classes": "^7.1.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-dotall-regex": "^7.0.0", - "@babel/plugin-transform-duplicate-keys": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.1.0", - "@babel/plugin-transform-for-of": "^7.0.0", - "@babel/plugin-transform-function-name": "^7.1.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-modules-amd": "^7.1.0", - "@babel/plugin-transform-modules-commonjs": "^7.1.0", - "@babel/plugin-transform-modules-systemjs": "^7.0.0", - "@babel/plugin-transform-modules-umd": "^7.1.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.1.0", - "@babel/plugin-transform-parameters": "^7.1.0", - "@babel/plugin-transform-regenerator": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-sticky-regex": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", - "@babel/plugin-transform-typeof-symbol": "^7.0.0", - "@babel/plugin-transform-unicode-regex": "^7.0.0", - "browserslist": "^4.1.0", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.3.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/preset-react": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", - "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-preset-react-app/node_modules/@babel/runtime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", - "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", - "dependencies": { - "regenerator-runtime": "^0.12.0" - } - }, - "node_modules/babel-preset-react-app/node_modules/babel-plugin-dynamic-import-node": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.2.0.tgz", - "integrity": "sha512-fP899ELUnTaBcIzmrW7nniyqqdYWrWuJUyPWHxFa/c7r7hS6KC8FscNfLlBNIoPSc55kYMGEEKjPjJGCLbE1qA==", - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-preset-react-app/node_modules/regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" - }, - "node_modules/babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dependencies": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - } - }, - "node_modules/babel-register/node_modules/babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dependencies": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "node_modules/babel-register/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/babel-register/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/babel-register/node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dependencies": { - "source-map": "^0.5.6" - } - }, - "node_modules/babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dependencies": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "node_modules/babel-runtime/node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "node_modules/babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dependencies": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "node_modules/babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dependencies": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "node_modules/babel-traverse/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/babel-traverse/node_modules/globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babel-traverse/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dependencies": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "node_modules/babel-types/node_modules/to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "bin": { - "babylon": "bin/babylon.js" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/bfj": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.1.tgz", - "integrity": "sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ==", - "dependencies": { - "bluebird": "^3.5.1", - "check-types": "^7.3.0", - "hoopy": "^0.1.2", - "tryer": "^1.0.0" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "node_modules/bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "node_modules/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", - "dependencies": { - "bytes": "3.1.1", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.6", - "raw-body": "2.4.2", - "type-is": "~1.6.18" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dependencies": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "node_modules/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==" - }, - "node_modules/browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dependencies": { - "resolve": "1.1.7" - } - }, - "node_modules/browser-resolve/node_modules/resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "dependencies": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "node_modules/browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "dependencies": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/browserify-optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", - "integrity": "sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk=", - "dependencies": { - "ast-transform": "0.0.0", - "ast-types": "^0.7.0", - "browser-resolve": "^1.8.1" - } - }, - "node_modules/browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "dependencies": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "node_modules/browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "dependencies": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "node_modules/browserify-sign/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/browserify-sign/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "dependencies": { - "pako": "~1.0.5" - } - }, - "node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "dependencies": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "node_modules/bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "hasInstallScript": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", - "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", - "dependencies": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" - }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dependencies": { - "callsites": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dependencies": { - "caller-callsite": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "engines": { - "node": ">=4" - } - }, - "node_modules/camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "dependencies": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } - }, - "node_modules/capture-exit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz", - "integrity": "sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28=", - "dependencies": { - "rsvp": "^3.3.3" - } - }, - "node_modules/case-sensitive-paths-webpack-plugin": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.2.tgz", - "integrity": "sha512-oEZgAFfEvKtjSRCu6VgYkuGxwrWXMnQzyBmlLPP7r6PWQVtHxP5Z5N6XsuJvtoVax78am/r7lr46bwo3IVEBOg==", - "engines": { - "node": ">=4" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, - "node_modules/check-types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz", - "integrity": "sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg==" - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "optional": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "optional": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/chokidar/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "optional": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "optional": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "optional": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chokidar/node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "optional": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "optional": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/chokidar/node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chokidar/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "optional": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "engines": { - "node": ">=6.0" - } - }, - "node_modules/ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" - }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "deprecated": "CircularJSON is in maintenance only, flatted is its successor." - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" - }, - "node_modules/clean-css": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", - "dependencies": { - "source-map": "~0.6.0" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/clean-css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" - }, - "node_modules/cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dependencies": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "node_modules/clone-deep": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", - "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", - "dependencies": { - "for-own": "^0.1.3", - "is-plain-object": "^2.0.1", - "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", - "shallow-clone": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "dependencies": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "node_modules/color-string": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", - "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" - }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "node_modules/constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, - "node_modules/contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "node_modules/copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dependencies": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true - }, - "node_modules/core-js-compat": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", - "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", - "dependencies": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "dependencies": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - } - }, - "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "dependencies": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - }, - "engines": { - "node": "*" - } - }, - "node_modules/css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", - "engines": { - "node": "*" - } - }, - "node_modules/css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "dependencies": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - }, - "engines": { - "node": ">4" - } - }, - "node_modules/css-declaration-sorter/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/css-declaration-sorter/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/css-declaration-sorter/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-loader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.0.tgz", - "integrity": "sha512-tMXlTYf3mIMt3b0dDCOQFJiVvxbocJ5Ho577WiGPYPZcqVEO218L2iU22pDXzkTZCLDE+9AmGSUkWxeh/nZReA==", - "dependencies": { - "babel-code-frame": "^6.26.0", - "css-selector-tokenizer": "^0.7.0", - "icss-utils": "^2.1.0", - "loader-utils": "^1.0.2", - "lodash.camelcase": "^4.3.0", - "postcss": "^6.0.23", - "postcss-modules-extract-imports": "^1.2.0", - "postcss-modules-local-by-default": "^1.2.0", - "postcss-modules-scope": "^1.1.0", - "postcss-modules-values": "^1.3.0", - "postcss-value-parser": "^3.3.0", - "source-list-map": "^2.0.0" - }, - "engines": { - "node": ">= 6.9.0 <7.0.0 || >= 8.9.0" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } - }, - "node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" - }, - "node_modules/css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "dependencies": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, - "node_modules/css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "dependencies": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/css-tree/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssdb": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-3.2.1.tgz", - "integrity": "sha512-I0IS8zvxED8sQtFZnV7M+AkhWqTgp1HIyfMQJBbjdn4GgurBt7NCZaDgrWiAN2kNJN34mhF1p50aZIMQu290mA==" - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", - "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", - "dependencies": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.8", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "dependencies": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-preset-default/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/cssnano-preset-default/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/cssnano-preset-default/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano-util-raw-cache/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/cssnano-util-raw-cache/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/cssnano-util-raw-cache/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/cssnano/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/cssnano/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/cssnano/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "dependencies": { - "css-tree": "^1.1.2" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "dependencies": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "node_modules/csso/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" - }, - "node_modules/cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" - }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-urls": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.1.tgz", - "integrity": "sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw==", - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^10.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==" - }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "node_modules/default-gateway": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.2.tgz", - "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==", - "os": [ - "android", - "darwin", - "freebsd", - "linux", - "openbsd", - "sunos", - "win32" - ], - "dependencies": { - "execa": "^0.10.0", - "ip-regex": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", - "dependencies": { - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", - "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", - "dependencies": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/del/node_modules/globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dependencies": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "dependencies": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "node_modules/detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dependencies": { - "repeating": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "node_modules/detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "dependencies": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "bin": { - "detect": "bin/detect-port", - "detect-port": "bin/detect-port" - }, - "engines": { - "node": ">= 4.2.1" - } - }, - "node_modules/detect-port-alt/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/detect-port-alt/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "dependencies": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "dependencies": { - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/distance-to-line-segment": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/distance-to-line-segment/-/distance-to-line-segment-0.2.0.tgz", - "integrity": "sha1-5FQnu4Ng61mob/2YFKdXjdLD1nk=" - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" - }, - "node_modules/dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "dependencies": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dependencies": { - "buffer-indexof": "^1.0.0" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "dependencies": { - "utila": "~0.4" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "engines": { - "node": ">=0.4", - "npm": ">=1.2" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dot-prop/node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.0.0.tgz", - "integrity": "sha512-FlWbnhgjtwD+uNLUGHbMykMOYQaTivdHEmYwAKFjn6GKe/CqY0fNae93ZHTd20snh9ZLr8mTzIL9m0APQ1pjQg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/dotenv-expand": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", - "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=" - }, - "node_modules/draco3d": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.0.tgz", - "integrity": "sha512-8ESjH7o5xju1nfSvcS2A9vIbwSRQ3yYY0Yv7SFhNszsq4FlN4LGZuxNc3YfAPcg0AddaK0dE5AES3w1JoGeViA==" - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "node_modules/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/earcut": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", - "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==" - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "node_modules/electron-to-chromium": { - "version": "1.4.68", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz", - "integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA==" - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/emoji-regex": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", - "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==" - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", - "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", - "dependencies": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/enhanced-resolve/node_modules/memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", - "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - }, - "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.6.0.tgz", - "integrity": "sha512-/eVYs9VVVboX286mBK7bbKnO1yamUy2UCRjiY6MryhQL2PaaXCExsCQ2aO83OeYRhU2eCU/FMFP+tVMoOrzNrA==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.12.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^2.0.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^4.0.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^6.14.0 || ^8.10.0 || >=9.10.0" - } - }, - "node_modules/eslint-config-react-app": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-3.0.8.tgz", - "integrity": "sha512-Ovi6Bva67OjXrom9Y/SLJRkrGqKhMAL0XCH8BizPhjEVEhYczl2ZKiNZI2CuqO5/CJwAfMwRXAVGY0KToWr1aA==", - "dependencies": { - "confusing-browser-globals": "^1.0.6" - }, - "peerDependencies": { - "babel-eslint": "9.x", - "eslint": "5.x", - "eslint-plugin-flowtype": "2.x", - "eslint-plugin-import": "2.x", - "eslint-plugin-jsx-a11y": "6.x", - "eslint-plugin-react": "7.x" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "dependencies": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.1.tgz", - "integrity": "sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==", - "deprecated": "This loader has been deprecated. Please use eslint-webpack-plugin", - "dependencies": { - "loader-fs-cache": "^1.0.0", - "loader-utils": "^1.0.2", - "object-assign": "^4.0.1", - "object-hash": "^1.1.4", - "rimraf": "^2.6.1" - }, - "peerDependencies": { - "eslint": ">=1.6.0 <6.0.0", - "webpack": ">=2.0.0 <5.0.0" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "dependencies": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-flowtype": { - "version": "2.50.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.1.tgz", - "integrity": "sha512-9kRxF9hfM/O6WGZcZPszOVPd2W0TLHBtceulLTsGfwMPtiCCLnCW0ssRiOOiXyqrCA20pm1iXdXm7gQeN306zQ==", - "dependencies": { - "lodash": "^4.17.10" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": ">=2.0.0" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", - "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", - "dependencies": { - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "2.x - 5.x" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dependencies": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.1.tgz", - "integrity": "sha512-JsxNKqa3TwmPypeXNnI75FntkUktGzI1wSa1LgNZdSOMI+B4sxnr1lSF8m8lPiz4mKiC+14ysZQM4scewUrP7A==", - "dependencies": { - "aria-query": "^3.0.0", - "array-includes": "^3.0.3", - "ast-types-flow": "^0.0.7", - "axobject-query": "^2.0.1", - "damerau-levenshtein": "^1.0.4", - "emoji-regex": "^6.5.1", - "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", - "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", - "dependencies": { - "array-includes": "^3.0.3", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.2" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", - "dependencies": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eve": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/eve/-/eve-0.5.4.tgz", - "integrity": "sha1-Z9CAuXJSkdfjieNMJoYN2X8d66o=" - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/eventsource": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", - "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", - "dependencies": { - "original": ">=0.0.5" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/exec-sh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", - "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", - "dependencies": { - "merge": "^1.2.0" - } - }, - "node_modules/execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dependencies": { - "is-posix-bracket": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dependencies": { - "fill-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expect": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz", - "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==", - "dependencies": { - "ansi-styles": "^3.2.0", - "jest-diff": "^23.6.0", - "jest-get-type": "^22.1.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0" - } - }, - "node_modules/expect/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/expect/node_modules/jest-diff": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", - "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", - "dependencies": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - } - }, - "node_modules/expect/node_modules/jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "node_modules/expect/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/express": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", - "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", - "dependencies": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.6", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", - "dependencies": { - "type": "^2.5.0" - } - }, - "node_modules/ext/node_modules/type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "node_modules/fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "dependencies": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/fast-glob/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/fast-glob/node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-glob/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "node_modules/fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" - }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dependencies": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/file-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz", - "integrity": "sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ==", - "dependencies": { - "loader-utils": "^1.0.2", - "schema-utils": "^1.0.0" - }, - "engines": { - "node": ">= 6.9.0 < 7.0.0 || >= 8.9.0" - }, - "peerDependencies": { - "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true - }, - "node_modules/filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fileset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", - "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", - "dependencies": { - "glob": "^7.0.3", - "minimatch": "^3.0.3" - } - }, - "node_modules/filesize": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", - "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dependencies": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "dependencies": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/flatten": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", - "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", - "deprecated": "flatten is deprecated in favor of utility frameworks such as lodash." - }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "node_modules/follow-redirects": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/fs-extra": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz", - "integrity": "sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dependencies": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", - "bundleDependencies": [ - "node-pre-gyp" - ], - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fsevents/node_modules/abbrev": { - "version": "1.1.1", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/ansi-regex": { - "version": "2.1.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/aproba": { - "version": "1.2.0", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/are-we-there-yet": { - "version": "1.1.4", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/fsevents/node_modules/balanced-match": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/brace-expansion": { - "version": "1.1.11", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/fsevents/node_modules/chownr": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/code-point-at": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/concat-map": { - "version": "0.0.1", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/console-control-strings": { - "version": "1.1.0", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/core-util-is": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/debug": { - "version": "2.6.9", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/fsevents/node_modules/deep-extend": { - "version": "0.5.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/delegates": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/detect-libc": { - "version": "1.0.3", - "inBundle": true, - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/fsevents/node_modules/fs-minipass": { - "version": "1.2.5", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^2.2.1" - } - }, - "node_modules/fsevents/node_modules/fs.realpath": { - "version": "1.0.0", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/gauge": { - "version": "2.7.4", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/fsevents/node_modules/glob": { - "version": "7.1.2", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "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" - }, - "engines": { - "node": "*" - } - }, - "node_modules/fsevents/node_modules/has-unicode": { - "version": "2.0.1", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/iconv-lite": { - "version": "0.4.21", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/ignore-walk": { - "version": "3.0.1", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minimatch": "^3.0.4" - } - }, - "node_modules/fsevents/node_modules/inflight": { - "version": "1.0.6", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/fsevents/node_modules/inherits": { - "version": "2.0.3", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/ini": { - "version": "1.3.5", - "inBundle": true, - "license": "ISC", - "optional": true, - "engines": { - "node": "*" - } - }, - "node_modules/fsevents/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/isarray": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/minimatch": { - "version": "3.0.4", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/fsevents/node_modules/minimist": { - "version": "0.0.8", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/minipass": { - "version": "2.2.4", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "node_modules/fsevents/node_modules/minizlib": { - "version": "1.1.0", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^2.2.1" - } - }, - "node_modules/fsevents/node_modules/mkdirp": { - "version": "0.5.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "minimist": "0.0.8" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/fsevents/node_modules/ms": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/needle": { - "version": "2.2.0", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 0.10.x" - } - }, - "node_modules/fsevents/node_modules/node-pre-gyp": { - "version": "0.10.0", - "inBundle": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/fsevents/node_modules/nopt": { - "version": "4.0.1", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/fsevents/node_modules/npm-bundled": { - "version": "1.0.3", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/npm-packlist": { - "version": "1.1.10", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "node_modules/fsevents/node_modules/npmlog": { - "version": "4.1.2", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/fsevents/node_modules/number-is-nan": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/object-assign": { - "version": "4.1.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/once": { - "version": "1.4.0", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/fsevents/node_modules/os-homedir": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/os-tmpdir": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/osenv": { - "version": "0.1.5", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/fsevents/node_modules/path-is-absolute": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/process-nextick-args": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/rc": { - "version": "1.2.7", - "inBundle": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "optional": true, - "dependencies": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/fsevents/node_modules/rc/node_modules/minimist": { - "version": "1.2.0", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/readable-stream": { - "version": "2.3.6", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "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" - } - }, - "node_modules/fsevents/node_modules/rimraf": { - "version": "2.6.2", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "glob": "^7.0.5" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/fsevents/node_modules/safe-buffer": { - "version": "5.1.1", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/safer-buffer": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/sax": { - "version": "1.2.4", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/semver": { - "version": "5.5.0", - "inBundle": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/fsevents/node_modules/set-blocking": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/signal-exit": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/string_decoder": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/fsevents/node_modules/string-width": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/strip-ansi": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/strip-json-comments": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fsevents/node_modules/tar": { - "version": "4.4.1", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" - }, - "engines": { - "node": ">=4.5" - } - }, - "node_modules/fsevents/node_modules/util-deprecate": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/wide-align": { - "version": "1.1.2", - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "string-width": "^1.0.2" - } - }, - "node_modules/fsevents/node_modules/wrappy": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/yallist": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" - }, - "node_modules/get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", - "engines": { - "node": ">=4" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/gl-matrix": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dependencies": { - "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" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dependencies": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dependencies": { - "is-glob": "^2.0.0" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" - }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globby": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", - "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", - "dependencies": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/globby/node_modules/ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "node_modules/growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" - }, - "node_modules/gzip-size": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", - "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==", - "dependencies": { - "duplexer": "^0.1.1", - "pify": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/h2x-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/h2x-core/-/h2x-core-1.1.1.tgz", - "integrity": "sha512-LdXe4Irs731knLtHgLyFrnJCumfiqXXQwKN1IMUhi37li29PLfLbMDvfK7Rk4wmgHLKP+sIITT1mcJV4QsC3nw==", - "dependencies": { - "h2x-generate": "^1.1.0", - "h2x-parse": "^1.1.1", - "h2x-traverse": "^1.1.0" - } - }, - "node_modules/h2x-generate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/h2x-generate/-/h2x-generate-1.1.0.tgz", - "integrity": "sha512-L7Hym0yb20QIjvqeULUPOeh/cyvScdOAyJ6oRlh5dF0+w92hf3OiTk1q15KBijde7jGEe+0R4aOmtW8gkPNIzg==", - "dependencies": { - "h2x-traverse": "^1.1.0" - } - }, - "node_modules/h2x-parse": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/h2x-parse/-/h2x-parse-1.1.1.tgz", - "integrity": "sha512-WRSmPF+tIWuUXVEZaYRhcZx/JGEJx8LjZpDDtrvMr5m/GTR0NerydCik5dRzcKXPWCtfXxuJRLR4v2P4HB2B1A==", - "dependencies": { - "h2x-types": "^1.1.0", - "jsdom": ">=11.0.0" - } - }, - "node_modules/h2x-plugin-jsx": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/h2x-plugin-jsx/-/h2x-plugin-jsx-1.2.0.tgz", - "integrity": "sha512-a7Vb3BHhJJq0dPDNdqguEyQirENkVsFtvM2YkiaT5h/fmGhmM1nDy3BLeJeSKi2tL2g9v4ykm2Z+GG9QrhDgPA==", - "dependencies": { - "h2x-types": "^1.1.0" - } - }, - "node_modules/h2x-traverse": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/h2x-traverse/-/h2x-traverse-1.1.0.tgz", - "integrity": "sha512-1ND8ZbISLSUgpLHYJRvhvElITvs0g44L7RxjeXViz5XP6rooa+FtXTFLByl2Yg01zj2txubifHIuU4pgvj8l+A==", - "dependencies": { - "h2x-types": "^1.1.0" - } - }, - "node_modules/h2x-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/h2x-types/-/h2x-types-1.1.0.tgz", - "integrity": "sha512-QdH5qfLcdF209UsCdM0ZNZ9Dwm2PHvMfeLZtivBrjX3Y/df4US2pwsUC4HBfWhye/mx/t6puODeC7Oacb/Ol8g==" - }, - "node_modules/handle-thing": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", - "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=" - }, - "node_modules/handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/handlebars/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hash-base/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/hash-base/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, - "node_modules/hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" - }, - "node_modules/history": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", - "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", - "dependencies": { - "@babel/runtime": "^7.7.6" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", - "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" - }, - "node_modules/hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" - }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-entities": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" - }, - "node_modules/html-minifier": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", - "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", - "dependencies": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - }, - "bin": { - "html-minifier": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/html-minifier/node_modules/commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" - }, - "node_modules/html-webpack-plugin": { - "version": "4.0.0-alpha.2", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-alpha.2.tgz", - "integrity": "sha512-tyvhjVpuGqD7QYHi1l1drMQTg5i+qRxpQEGbdnYFREgOKy7aFDf/ocQ/V1fuEDlQx7jV2zMap3Hj2nE9i5eGXw==", - "deprecated": "please switch to a stable version", - "dependencies": { - "@types/tapable": "1.0.2", - "html-minifier": "^3.2.3", - "loader-utils": "^1.1.0", - "lodash": "^4.17.10", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", - "util.promisify": "1.0.0" - }, - "engines": { - "node": ">=6.9" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } - }, - "node_modules/html-webpack-plugin/node_modules/util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dependencies": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" - }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/http-proxy-middleware": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", - "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", - "dependencies": { - "http-proxy": "^1.16.2", - "is-glob": "^4.0.0", - "lodash": "^4.17.5", - "micromatch": "^3.1.9" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/http-proxy-middleware/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, - "node_modules/https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" - }, - "node_modules/icss-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", - "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", - "dependencies": { - "postcss": "^6.0.1" - } - }, - "node_modules/identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", - "dependencies": { - "harmony-reflect": "^1.4.6" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "engines": { - "node": ">= 4" - } - }, - "node_modules/immer": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/immer/-/immer-1.7.2.tgz", - "integrity": "sha512-4Urocwu9+XLDJw4Tc6ZCg7APVjjLInCFvO4TwGsAYV5zT6YYSor14dsZR0+0tHlDIN92cFUOq+i7fC00G5vTxA==" - }, - "node_modules/import-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", - "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "dependencies": { - "import-from": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-from": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", - "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/import-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", - "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", - "dependencies": { - "pkg-dir": "^2.0.0", - "resolve-cwd": "^2.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/internal-ip": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz", - "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==", - "os": [ - "android", - "darwin", - "freebsd", - "linux", - "openbsd", - "sunos", - "win32" - ], - "dependencies": { - "default-gateway": "^2.6.0", - "ipaddr.js": "^1.5.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "node_modules/ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "engines": { - "node": ">=4" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "optional": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "dependencies": { - "ci-info": "^1.5.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "dependencies": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dependencies": { - "is-primitive": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "engines": { - "node": ">=4" - } - }, - "node_modules/is-generator-fn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", - "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dependencies": { - "is-extglob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dependencies": { - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dependencies": { - "path-is-inside": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" - }, - "node_modules/is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" - }, - "node_modules/is-root": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.0.0.tgz", - "integrity": "sha512-F/pJIk8QD6OX5DNhRB7hWamLsUilmkDGho48KbgZ6xg/lmAZXHxzXQ91jzB3yRSw5kdQGGGc4yz8HYhTYIMWPg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "node_modules/isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "dependencies": { - "punycode": "2.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "node_modules/istanbul-api": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", - "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", - "dependencies": { - "async": "^2.1.4", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.2.1", - "istanbul-lib-hook": "^1.2.2", - "istanbul-lib-instrument": "^1.10.2", - "istanbul-lib-report": "^1.1.5", - "istanbul-lib-source-maps": "^1.2.6", - "istanbul-reports": "^1.5.1", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", - "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==" - }, - "node_modules/istanbul-lib-hook": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", - "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", - "dependencies": { - "append-transform": "^0.4.0" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", - "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", - "dependencies": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.1", - "semver": "^5.3.0" - } - }, - "node_modules/istanbul-lib-report": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", - "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", - "dependencies": { - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dependencies": { - "has-flag": "^1.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", - "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", - "dependencies": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - } - }, - "node_modules/istanbul-reports": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", - "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", - "dependencies": { - "handlebars": "^4.0.3" - } - }, - "node_modules/jest": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-23.6.0.tgz", - "integrity": "sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==", - "dependencies": { - "import-local": "^1.0.0", - "jest-cli": "^23.6.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/jest-changed-files": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-23.4.2.tgz", - "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==", - "dependencies": { - "throat": "^4.0.0" - } - }, - "node_modules/jest-cli": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.6.0.tgz", - "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==", - "dependencies": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "import-local": "^1.0.0", - "is-ci": "^1.0.10", - "istanbul-api": "^1.3.1", - "istanbul-lib-coverage": "^1.2.0", - "istanbul-lib-instrument": "^1.10.1", - "istanbul-lib-source-maps": "^1.2.4", - "jest-changed-files": "^23.4.2", - "jest-config": "^23.6.0", - "jest-environment-jsdom": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve-dependencies": "^23.6.0", - "jest-runner": "^23.6.0", - "jest-runtime": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "jest-watcher": "^23.4.0", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "node-notifier": "^5.2.1", - "prompts": "^0.1.9", - "realpath-native": "^1.0.0", - "rimraf": "^2.5.4", - "slash": "^1.0.0", - "string-length": "^2.0.0", - "strip-ansi": "^4.0.0", - "which": "^1.2.12", - "yargs": "^11.0.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/jest-cli/node_modules/jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "node_modules/jest-config": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.6.0.tgz", - "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==", - "dependencies": { - "babel-core": "^6.0.0", - "babel-jest": "^23.6.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^23.4.0", - "jest-environment-node": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-jasmine2": "^23.6.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-config/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-config/node_modules/babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dependencies": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "node_modules/jest-config/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/jest-config/node_modules/jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "node_modules/jest-config/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/jest-config/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/jest-docblock": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-23.2.0.tgz", - "integrity": "sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c=", - "dependencies": { - "detect-newline": "^2.1.0" - } - }, - "node_modules/jest-each": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz", - "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==", - "dependencies": { - "chalk": "^2.0.1", - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-each/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz", - "integrity": "sha1-BWp5UrP+pROsYqFAosNox52eYCM=", - "dependencies": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0", - "jsdom": "^11.5.1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dependencies": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/acorn-globals/node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" - }, - "node_modules/jest-environment-jsdom/node_modules/cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "dependencies": { - "cssom": "0.3.x" - } - }, - "node_modules/jest-environment-jsdom/node_modules/data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dependencies": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/data-urls/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dependencies": { - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/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==", - "dependencies": { - "whatwg-encoding": "^1.0.1" - } - }, - "node_modules/jest-environment-jsdom/node_modules/jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dependencies": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" - }, - "node_modules/jest-environment-jsdom/node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/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==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/jest-environment-jsdom/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/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==" - }, - "node_modules/jest-environment-jsdom/node_modules/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==", - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/jest-environment-jsdom/node_modules/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==" - }, - "node_modules/jest-environment-jsdom/node_modules/whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/jest-environment-jsdom/node_modules/ws": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", - "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", - "dependencies": { - "async-limiter": "~1.0.0" - } - }, - "node_modules/jest-environment-jsdom/node_modules/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==" - }, - "node_modules/jest-environment-node": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-23.4.0.tgz", - "integrity": "sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA=", - "dependencies": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0" - } - }, - "node_modules/jest-haste-map": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.6.0.tgz", - "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==", - "dependencies": { - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.1.11", - "invariant": "^2.2.4", - "jest-docblock": "^23.2.0", - "jest-serializer": "^23.0.1", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "sane": "^2.0.0" - } - }, - "node_modules/jest-jasmine2": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz", - "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==", - "dependencies": { - "babel-traverse": "^6.0.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^23.6.0", - "is-generator-fn": "^1.0.0", - "jest-diff": "^23.6.0", - "jest-each": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-jasmine2/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-diff": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", - "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", - "dependencies": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-jasmine2/node_modules/jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "node_modules/jest-jasmine2/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/jest-leak-detector": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz", - "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==", - "dependencies": { - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-leak-detector/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz", - "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==", - "dependencies": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-matcher-utils/node_modules/jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/jest-message-util": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-23.4.0.tgz", - "integrity": "sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8=", - "dependencies": { - "@babel/code-frame": "^7.0.0-beta.35", - "chalk": "^2.0.1", - "micromatch": "^2.3.11", - "slash": "^1.0.0", - "stack-utils": "^1.0.1" - } - }, - "node_modules/jest-mock": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-23.2.0.tgz", - "integrity": "sha1-rRxg8p6HGdR8JuETgJi20YsmETQ=" - }, - "node_modules/jest-pnp-resolver": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.0.1.tgz", - "integrity": "sha512-kzhvJQp+9k0a/hpvIIzOJgOwfOqmnohdrAMZW2EscH3kxR2VWD7EcPa10cio8EK9V7PcD75bhG1pFnO70zGwSQ==", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - } - }, - "node_modules/jest-regex-util": { - "version": "23.3.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-23.3.0.tgz", - "integrity": "sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U=" - }, - "node_modules/jest-resolve": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz", - "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==", - "dependencies": { - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "realpath-native": "^1.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz", - "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==", - "dependencies": { - "jest-regex-util": "^23.3.0", - "jest-snapshot": "^23.6.0" - } - }, - "node_modules/jest-runner": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.6.0.tgz", - "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==", - "dependencies": { - "exit": "^0.1.2", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-docblock": "^23.2.0", - "jest-haste-map": "^23.6.0", - "jest-jasmine2": "^23.6.0", - "jest-leak-detector": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-runtime": "^23.6.0", - "jest-util": "^23.4.0", - "jest-worker": "^23.2.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.6.0.tgz", - "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==", - "dependencies": { - "babel-core": "^6.0.0", - "babel-plugin-istanbul": "^4.1.6", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "exit": "^0.1.2", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "realpath-native": "^1.0.0", - "slash": "^1.0.0", - "strip-bom": "3.0.0", - "write-file-atomic": "^2.1.0", - "yargs": "^11.0.0" - }, - "bin": { - "jest-runtime": "bin/jest-runtime.js" - } - }, - "node_modules/jest-runtime/node_modules/babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dependencies": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "node_modules/jest-runtime/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/jest-runtime/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/jest-runtime/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-serializer": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-23.0.1.tgz", - "integrity": "sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU=" - }, - "node_modules/jest-snapshot": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.6.0.tgz", - "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==", - "dependencies": { - "babel-types": "^6.0.0", - "chalk": "^2.0.1", - "jest-diff": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-resolve": "^23.6.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^23.6.0", - "semver": "^5.5.0" - } - }, - "node_modules/jest-snapshot/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-snapshot/node_modules/jest-diff": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", - "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", - "dependencies": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-snapshot/node_modules/jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "node_modules/jest-snapshot/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/jest-util": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-23.4.0.tgz", - "integrity": "sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE=", - "dependencies": { - "callsites": "^2.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.11", - "is-ci": "^1.0.10", - "jest-message-util": "^23.4.0", - "mkdirp": "^0.5.1", - "slash": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/jest-util/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-validate": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", - "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", - "dependencies": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" - } - }, - "node_modules/jest-validate/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/jest-validate/node_modules/jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "node_modules/jest-validate/node_modules/pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "dependencies": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - }, - "node_modules/jest-watcher": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-23.4.0.tgz", - "integrity": "sha1-0uKM50+NrWxq/JIrksq+9u0FyRw=", - "dependencies": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "string-length": "^2.0.0" - } - }, - "node_modules/jest-worker": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz", - "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", - "dependencies": { - "merge-stream": "^1.0.1" - } - }, - "node_modules/joi": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", - "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", - "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", - "dependencies": { - "hoek": "4.x.x", - "isemail": "3.x.x", - "topo": "2.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "node_modules/jsdom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", - "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.5.0", - "acorn-globals": "^6.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.1", - "decimal.js": "^10.3.1", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^3.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^10.0.0", - "ws": "^8.2.3", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "node_modules/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==" - }, - "node_modules/json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dependencies": { - "jsonify": "~0.0.0" - } - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "node_modules/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=" - }, - "node_modules/json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" - }, - "node_modules/json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "engines": { - "node": "*" - } - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/jsx-ast-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", - "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", - "dependencies": { - "array-includes": "^3.1.1", - "object.assign": "^4.1.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" - }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/kleur": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", - "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", - "deprecated": "Please upgrade to kleur@3 or migrate to 'ansi-colors' if you prefer the old syntax. Visit for migration path(s).", - "engines": { - "node": ">=6" - } - }, - "node_modules/last-call-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", - "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", - "dependencies": { - "lodash": "^4.17.5", - "webpack-sources": "^1.1.0" - } - }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dependencies": { - "invert-kv": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "deprecated": "use String.prototype.padStart()" - }, - "node_modules/leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/load-json-file/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file/node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "engines": { - "node": ">=4" - } - }, - "node_modules/loader-fs-cache": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", - "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", - "dependencies": { - "find-cache-dir": "^0.1.1", - "mkdirp": "^0.5.1" - } - }, - "node_modules/loader-fs-cache/node_modules/find-cache-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", - "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", - "dependencies": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-fs-cache/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-fs-cache/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-fs-cache/node_modules/pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dependencies": { - "find-up": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "engines": { - "node": ">=4.3.0 <5.0.0 || >=5.10" - } - }, - "node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/loader-utils/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" - }, - "node_modules/lodash.tail": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", - "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=" - }, - "node_modules/lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "dependencies": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "node_modules/loglevel": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", - "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", - "engines": { - "node": ">= 0.6.0" - }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/loglevel" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/mamacro": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" - }, - "node_modules/map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dependencies": { - "p-defer": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dependencies": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/mem/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" - }, - "node_modules/memoize-weak": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/memoize-weak/-/memoize-weak-1.0.2.tgz", - "integrity": "sha1-0AFaTHxs/yJj27tJ2x3CBuu5SRY=" - }, - "node_modules/memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "dependencies": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "node_modules/merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==" - }, - "node_modules/merge-deep": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", - "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", - "dependencies": { - "arr-union": "^3.1.0", - "clone-deep": "^0.2.4", - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "node_modules/merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dependencies": { - "readable-stream": "^2.0.1" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dependencies": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "dependencies": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "bin": { - "miller-rabin": "bin/miller-rabin" - } - }, - "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.3.tgz", - "integrity": "sha512-Mxs0nxzF1kxPv4TRi2NimewgXlJqh0rGE30vviCU2WHrpbta6wklnUV9dr9FUtoAHmB3p3LeXEC+ZjgHvB0Dzg==", - "dependencies": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" - }, - "engines": { - "node": ">= 6.9.0 <7.0.0 || >= 8.9.0" - }, - "peerDependencies": { - "webpack": "^4.4.0" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "node_modules/minimatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.1.tgz", - "integrity": "sha512-reLxBcKUPNBnc/sVtAbxgRVFSegoGeLaSjmphNhcwcolhYLRgtJscn5mRl6YRZNQv40Y7P6JM2YhSIsbL9OB5A==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "node_modules/mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dependencies": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", - "dependencies": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-object/node_modules/for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "dependencies": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dependencies": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, - "node_modules/nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "optional": true - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "node_modules/no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", - "dependencies": { - "lower-case": "^1.1.1" - } - }, - "node_modules/node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" - }, - "node_modules/node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "dependencies": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - } - }, - "node_modules/node-libs-browser/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/node-libs-browser/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "node_modules/node-libs-browser/node_modules/util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "dependencies": { - "inherits": "2.0.3" - } - }, - "node_modules/node-notifier": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", - "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", - "dependencies": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-wheel": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", - "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" - }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==" - }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "engines": { - "node": "*" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dependencies": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/opn": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", - "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", - "dependencies": { - "is-wsl": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/optimize-css-assets-webpack-plugin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", - "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", - "dependencies": { - "cssnano": "^4.1.0", - "last-call-webpack-plugin": "^3.0.0" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dependencies": { - "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" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/original": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", - "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "dependencies": { - "url-parse": "^1.4.3" - } - }, - "node_modules/os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dependencies": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/os-locale/node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/os-locale/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "engines": { - "node": ">=4" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "node_modules/parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "dependencies": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "node_modules/param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "dependencies": { - "no-case": "^2.2.0" - } - }, - "node_modules/parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "dependencies": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dependencies": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "engines": { - "node": ">=4" - } - }, - "node_modules/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=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "optional": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "engines": { - "node": ">=4" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "dependencies": { - "find-up": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "engines": { - "node": ">=4" - } - }, - "node_modules/pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" - }, - "node_modules/pnp-webpack-plugin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.1.0.tgz", - "integrity": "sha512-CPCdcFxx7fEcDMWTDjXe2Wypt4JuMt4q5Q2UrpTcyBBkLiCIyPEh/mCGmUWIcNkKGyXwQ9Y2wVhlKm6ketiBNQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "dependencies": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "dependencies": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", - "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^6.0.2" - } - }, - "node_modules/postcss-attribute-case-insensitive/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-attribute-case-insensitive/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-attribute-case-insensitive/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", - "dependencies": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - } - }, - "node_modules/postcss-calc/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-calc/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-calc/node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "node_modules/postcss-calc/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-color-functional-notation": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", - "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-functional-notation/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-color-functional-notation/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-functional-notation/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-color-hex-alpha": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", - "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", - "dependencies": { - "postcss": "^7.0.14", - "postcss-values-parser": "^2.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-hex-alpha/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-color-hex-alpha/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-hex-alpha/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-color-mod-function": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", - "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", - "dependencies": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-mod-function/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-color-mod-function/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-mod-function/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-color-rebeccapurple": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", - "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-color-rebeccapurple/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-color-rebeccapurple/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-color-rebeccapurple/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "dependencies": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-colormin/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-colormin/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-colormin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-convert-values/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-convert-values/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-convert-values/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-custom-media": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", - "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", - "dependencies": { - "postcss": "^7.0.14" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-custom-media/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-custom-media/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-custom-media/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-custom-properties": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", - "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", - "dependencies": { - "postcss": "^7.0.17", - "postcss-values-parser": "^2.0.1" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-custom-properties/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-custom-properties/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-custom-properties/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-custom-selectors": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", - "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-custom-selectors/node_modules/cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-selectors/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-custom-selectors/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dependencies": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-custom-selectors/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-dir-pseudo-class": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", - "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-dir-pseudo-class/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dependencies": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-comments/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-discard-comments/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-comments/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-duplicates/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-discard-duplicates/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-duplicates/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-empty/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-discard-empty/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-empty/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-discard-overridden/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-discard-overridden/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-discard-overridden/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-env-function": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", - "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-env-function/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-env-function/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-env-function/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-flexbugs-fixes": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", - "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", - "dependencies": { - "postcss": "^7.0.0" - } - }, - "node_modules/postcss-flexbugs-fixes/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-flexbugs-fixes/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-flexbugs-fixes/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-focus-visible": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", - "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-focus-visible/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-focus-visible/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-focus-visible/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-focus-within": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", - "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-focus-within/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-focus-within/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-focus-within/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-font-variant": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", - "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-font-variant/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-font-variant/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-font-variant/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-gap-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", - "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-gap-properties/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-gap-properties/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-gap-properties/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-image-set-function": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", - "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-image-set-function/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-image-set-function/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-image-set-function/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-initial": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz", - "integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==", - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-initial/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-initial/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-initial/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-lab-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", - "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", - "dependencies": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-lab-function/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-lab-function/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-lab-function/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-load-config": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", - "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", - "dependencies": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", - "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", - "dependencies": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-loader/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-loader/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-logical": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", - "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-logical/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-logical/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-logical/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-media-minmax": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", - "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-media-minmax/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-media-minmax/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-media-minmax/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "dependencies": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-merge-longhand/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-merge-longhand/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-merge-longhand/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-merge-rules/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-merge-rules/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-merge-rules/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss-merge-rules/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-font-values/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-minify-font-values/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-font-values/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-gradients/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-minify-gradients/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-gradients/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "dependencies": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-params/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-minify-params/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-params/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "dependencies": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-minify-selectors/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-minify-selectors/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-minify-selectors/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss-minify-selectors/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", - "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", - "dependencies": { - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", - "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", - "dependencies": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-modules-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", - "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", - "dependencies": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-modules-values": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", - "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", - "dependencies": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^6.0.1" - } - }, - "node_modules/postcss-nesting": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", - "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-nesting/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-nesting/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-nesting/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-charset/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-charset/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-charset/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-display-values/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-display-values/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-display-values/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-positions/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-positions/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-positions/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-repeat-style/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-repeat-style/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-repeat-style/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "dependencies": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-string/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-string/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-string/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-timing-functions/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-timing-functions/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-timing-functions/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "dependencies": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-unicode/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-unicode/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-unicode/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "dependencies": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-url/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-url/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-url/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-normalize-whitespace/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-normalize-whitespace/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-normalize-whitespace/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "dependencies": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-ordered-values/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-ordered-values/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-ordered-values/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-overflow-shorthand": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", - "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", - "dependencies": { - "postcss": "^7.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-overflow-shorthand/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-overflow-shorthand/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-overflow-shorthand/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-page-break": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", - "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-page-break/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-page-break/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-page-break/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-place": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", - "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-place/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-place/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-place/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-preset-env": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.0.6.tgz", - "integrity": "sha512-W1Wtqngl7BMe4s9o76odTaVs4HXVLhOHD+L5Ez+7x15yiA+98W/WVO6IPlC1q9BIkgAckRtUFmEDr0sNufXZIQ==", - "dependencies": { - "autoprefixer": "^9.1.5", - "browserslist": "^4.1.1", - "caniuse-lite": "^1.0.30000887", - "cssdb": "^3.2.1", - "postcss": "^7.0.2", - "postcss-attribute-case-insensitive": "^4.0.0", - "postcss-color-functional-notation": "^2.0.1", - "postcss-color-hex-alpha": "^5.0.2", - "postcss-color-mod-function": "^3.0.3", - "postcss-color-rebeccapurple": "^4.0.1", - "postcss-custom-media": "^7.0.4", - "postcss-custom-properties": "^8.0.5", - "postcss-custom-selectors": "^5.1.2", - "postcss-dir-pseudo-class": "^5.0.0", - "postcss-env-function": "^2.0.2", - "postcss-focus-visible": "^4.0.0", - "postcss-focus-within": "^3.0.0", - "postcss-font-variant": "^4.0.0", - "postcss-gap-properties": "^2.0.0", - "postcss-image-set-function": "^3.0.1", - "postcss-initial": "^3.0.0", - "postcss-lab-function": "^2.0.1", - "postcss-logical": "^3.0.0", - "postcss-media-minmax": "^4.0.0", - "postcss-nesting": "^7.0.0", - "postcss-overflow-shorthand": "^2.0.0", - "postcss-page-break": "^2.0.0", - "postcss-place": "^4.0.1", - "postcss-pseudo-class-any-link": "^6.0.0", - "postcss-replace-overflow-wrap": "^3.0.0", - "postcss-selector-matches": "^4.0.0", - "postcss-selector-not": "^4.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-preset-env/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-preset-env/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-preset-env/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", - "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", - "dependencies": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "dependencies": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-reduce-initial/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-reduce-initial/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-reduce-initial/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "dependencies": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-reduce-transforms/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-reduce-transforms/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-reduce-transforms/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", - "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", - "dependencies": { - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-replace-overflow-wrap/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-replace-overflow-wrap/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-replace-overflow-wrap/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-safe-parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", - "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", - "dependencies": { - "postcss": "^7.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/postcss-safe-parser/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-safe-parser/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-safe-parser/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-selector-matches": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", - "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", - "dependencies": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-selector-matches/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-selector-matches/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-selector-matches/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-selector-not": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", - "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", - "dependencies": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - } - }, - "node_modules/postcss-selector-not/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-selector-not/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-selector-not/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "dependencies": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-svgo/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-svgo/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-svgo/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "dependencies": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/postcss-unique-selectors/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/postcss-unique-selectors/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-unique-selectors/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - }, - "node_modules/postcss-values-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", - "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", - "dependencies": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=6.14.4" - } - }, - "node_modules/postcss/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pretty-bytes": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", - "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", - "engines": { - "node": ">=4" - } - }, - "node_modules/pretty-error": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", - "dependencies": { - "lodash": "^4.17.20", - "renderkid": "^2.0.4" - } - }, - "node_modules/private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/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==" - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", - "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", - "dependencies": { - "asap": "~2.0.6" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" - }, - "node_modules/prompts": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", - "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", - "dependencies": { - "kleur": "^2.0.1", - "sisteransi": "^0.1.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "node_modules/public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "dependencies": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "engines": { - "node": ">=6" - } - }, - "node_modules/q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "node_modules/raf": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", - "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==", - "dependencies": { - "performance-now": "^2.1.0" - } - }, - "node_modules/randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "dependencies": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/randomatic/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/randomatic/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "dependencies": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", - "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", - "dependencies": { - "bytes": "3.1.1", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/react": { - "version": "16.8.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.8.0.tgz", - "integrity": "sha512-g+nikW2D48kqgWSPwNo0NH9tIGG3DsQFlrtrQ1kj6W77z5ahyIHG0w8kPpz4Sdj6gyLnz0lEd/xsjOoGge2MYQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-app-polyfill": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-0.1.3.tgz", - "integrity": "sha512-Fl5Pic4F15G05qX7RmUqPZr1MtyFKJKSlRwMhel4kvDLrk/KcQ9QbpvyMTzv/0NN5957XFQ7r1BNHWi7qN59Pw==", - "dependencies": { - "core-js": "2.5.7", - "object-assign": "4.1.1", - "promise": "8.0.2", - "raf": "3.4.0", - "whatwg-fetch": "3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-app-polyfill/node_modules/core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", - "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js." - }, - "node_modules/react-burger-menu": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/react-burger-menu/-/react-burger-menu-3.0.6.tgz", - "integrity": "sha512-Xikyl8VRkQBOyFVoMKpbScTLG6LlW64rajiquyCGwtpPswrDxaifusKckzTWAOH0At40Boguhj5lXq451NO0LA==", - "dependencies": { - "browserify-optional": "^1.0.0", - "classnames": "^2.2.6", - "eve": "~0.5.1", - "prop-types": "^15.7.2", - "snapsvg-cjs": "0.0.6" - }, - "engines": { - "node": ">=4.0.0" - }, - "peerDependencies": { - "react": ">=0.14.0 <18.0.0", - "react-dom": ">=0.14.0 <18.0.0" - } - }, - "node_modules/react-dev-utils": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-6.1.1.tgz", - "integrity": "sha512-ThbJ86coVd6wV/QiTo8klDTvdAJ1WsFCGQN07+UkN+QN9CtCSsl/+YuDJToKGeG8X4j9HMGXNKbk2QhPAZr43w==", - "dependencies": { - "@babel/code-frame": "7.0.0", - "address": "1.0.3", - "browserslist": "4.1.1", - "chalk": "2.4.1", - "cross-spawn": "6.0.5", - "detect-port-alt": "1.1.6", - "escape-string-regexp": "1.0.5", - "filesize": "3.6.1", - "find-up": "3.0.0", - "global-modules": "1.0.0", - "globby": "8.0.1", - "gzip-size": "5.0.0", - "immer": "1.7.2", - "inquirer": "6.2.0", - "is-root": "2.0.0", - "loader-utils": "1.1.0", - "opn": "5.4.0", - "pkg-up": "2.0.0", - "react-error-overlay": "^5.1.0", - "recursive-readdir": "2.2.2", - "shell-quote": "1.6.1", - "sockjs-client": "1.1.5", - "strip-ansi": "4.0.0", - "text-table": "0.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dev-utils/node_modules/@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dependencies": { - "@babel/highlight": "^7.0.0" - } - }, - "node_modules/react-dev-utils/node_modules/big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "engines": { - "node": "*" - } - }, - "node_modules/react-dev-utils/node_modules/browserslist": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.1.1.tgz", - "integrity": "sha512-VBorw+tgpOtZ1BYhrVSVTzTt/3+vSE3eFUh0N2GCFK1HffceOaf32YS/bs6WiFhjDAblAFrx85jMy3BG9fBK2Q==", - "dependencies": { - "caniuse-lite": "^1.0.30000884", - "electron-to-chromium": "^1.3.62", - "node-releases": "^1.0.0-alpha.11" - }, - "bin": { - "browserslist": "cli.js" - } - }, - "node_modules/react-dev-utils/node_modules/chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/react-dev-utils/node_modules/emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/react-dev-utils/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dev-utils/node_modules/inquirer": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", - "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", - "dependencies": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.0", - "figures": "^2.0.0", - "lodash": "^4.17.10", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.1.0", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/react-dev-utils/node_modules/loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dependencies": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/react-dev-utils/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dev-utils/node_modules/node-releases": { - "version": "1.1.77", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==" - }, - "node_modules/react-dev-utils/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-dev-utils/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dev-utils/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/react-dom": { - "version": "16.8.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.0.tgz", - "integrity": "sha512-dBzoAGYZpW9Yggp+CzBPC7q1HmWSeRc93DWrwbskmG1eHJWznZB/p0l/Sm+69leIGUS91AXPB/qB3WcPnKx8Sw==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.0" - }, - "peerDependencies": { - "react": "^16.0.0" - } - }, - "node_modules/react-error-overlay": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.6.tgz", - "integrity": "sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==" - }, - "node_modules/react-router": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.2.tgz", - "integrity": "sha512-/MbxyLzd7Q7amp4gDOGaYvXwhEojkJD5BtExkuKmj39VEE0m3l/zipf6h2WIB2jyAO0lI6NGETh4RDcktRm4AQ==", - "dependencies": { - "history": "^5.2.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.2.tgz", - "integrity": "sha512-AtYEsAST7bDD4dLSQHDnk/qxWLJdad5t1HFa1qJyUrCeGgEuCSw0VB/27ARbF9Fi/W5598ujvJOm3ujUCVzuYQ==", - "dependencies": { - "history": "^5.2.0", - "react-router": "6.2.2" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/react-scripts": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-2.0.3.tgz", - "integrity": "sha512-Hw6P9vJ9vXWdo5J752lzN6NpmY3DpEjp5VD+V+N+61TY5+UY/oKtfF+23ZRFBCkULlVvQdo25Sw92HKA2wI8sw==", - "dependencies": { - "@babel/core": "7.1.0", - "@svgr/webpack": "2.4.1", - "babel-core": "7.0.0-bridge.0", - "babel-eslint": "9.0.0", - "babel-jest": "23.6.0", - "babel-loader": "8.0.4", - "babel-plugin-named-asset-import": "^0.2.2", - "babel-preset-react-app": "^5.0.2", - "bfj": "6.1.1", - "case-sensitive-paths-webpack-plugin": "2.1.2", - "chalk": "2.4.1", - "css-loader": "1.0.0", - "dotenv": "6.0.0", - "dotenv-expand": "4.2.0", - "eslint": "5.6.0", - "eslint-config-react-app": "^3.0.3", - "eslint-loader": "2.1.1", - "eslint-plugin-flowtype": "2.50.1", - "eslint-plugin-import": "2.14.0", - "eslint-plugin-jsx-a11y": "6.1.1", - "eslint-plugin-react": "7.11.1", - "file-loader": "2.0.0", - "fs-extra": "7.0.0", - "html-webpack-plugin": "4.0.0-alpha.2", - "identity-obj-proxy": "3.0.0", - "jest": "23.6.0", - "jest-pnp-resolver": "1.0.1", - "jest-resolve": "23.6.0", - "mini-css-extract-plugin": "0.4.3", - "optimize-css-assets-webpack-plugin": "5.0.1", - "pnp-webpack-plugin": "1.1.0", - "postcss-flexbugs-fixes": "4.1.0", - "postcss-loader": "3.0.0", - "postcss-preset-env": "6.0.6", - "postcss-safe-parser": "4.0.1", - "react-app-polyfill": "^0.1.3", - "react-dev-utils": "^6.0.3", - "resolve": "1.8.1", - "sass-loader": "7.1.0", - "style-loader": "0.23.0", - "terser-webpack-plugin": "1.1.0", - "url-loader": "1.1.1", - "webpack": "4.19.1", - "webpack-dev-server": "3.1.9", - "webpack-manifest-plugin": "2.0.4", - "workbox-webpack-plugin": "3.6.2" - }, - "bin": { - "react-scripts": "bin/react-scripts.js" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "fsevents": "1.2.4" - } - }, - "node_modules/react-scripts/node_modules/chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dependencies": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dependencies": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dependencies": { - "pify": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/read-pkg/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "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" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "optional": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "dependencies": { - "util.promisify": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", - "dependencies": { - "minimatch": "3.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dependencies": { - "is-equal-shallow": "^0.1.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "engines": { - "node": ">=6.5.0" - } - }, - "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" - }, - "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/regl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/regl/-/regl-1.7.0.tgz", - "integrity": "sha512-bEAtp/qrtKucxXSJkD4ebopFZYP0q1+3Vb2WECWv/T8yQEgKxDxJ7ztO285tAMaYZVR6mM1GgI6CCn8FROtL1w==" - }, - "node_modules/regl-worldview": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/regl-worldview/-/regl-worldview-0.18.0.tgz", - "integrity": "sha512-/ZEmF/CKloZ0+0/AYrXYdQdLEHrjjLPp+vzhBmgVP/UIOrv+nt0BeRNM+xenRKknBuYE1M080q54M+aoJS9tDg==", - "dependencies": { - "@babel/runtime": "^7.3.1", - "@mapbox/tiny-sdf": "2.0.4", - "distance-to-line-segment": "0.2.0", - "draco3d": "^1.4.1", - "earcut": "^2.1.3", - "gl-matrix": ">=2.6.1", - "lodash": "^4.17.11", - "memoize-one": "^5.1.1", - "memoize-weak": "^1.0.2", - "normalize-wheel": "1.0.1", - "regl": "^1.3.1", - "reselect": "^3.0.1", - "shallowequal": "1.1.0" - }, - "peerDependencies": { - "react": "16.x", - "react-dom": "16.x" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "node_modules/renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", - "dependencies": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" - } - }, - "node_modules/renderkid/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/renderkid/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dependencies": { - "is-finite": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dependencies": { - "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" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dependencies": { - "lodash": "^4.17.19" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", - "dependencies": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "engines": { - "node": ">=0.12.0" - }, - "peerDependencies": { - "request": "^2.34" - } - }, - "node_modules/request-promise-native/node_modules/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==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/request/node_modules/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==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/request/node_modules/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==", - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "node_modules/require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dependencies": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-uncached/node_modules/caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dependencies": { - "callsites": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-uncached/node_modules/callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-uncached/node_modules/resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "node_modules/reselect": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", - "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" - }, - "node_modules/resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dependencies": { - "path-parse": "^1.0.5" - } - }, - "node_modules/resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dependencies": { - "resolve-from": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated" - }, - "node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "engines": { - "node": ">=0.12" - } - }, - "node_modules/rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" - }, - "node_modules/rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" - }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "node_modules/rsvp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", - "engines": { - "node": "0.12.* || 4.* || 6.* || >= 7.*" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "dependencies": { - "aproba": "^1.1.1" - } - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/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==" - }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sane": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz", - "integrity": "sha1-tNwYYcIbQn6SlQej51HiosuKs/o=", - "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", - "dependencies": { - "anymatch": "^2.0.0", - "capture-exit": "^1.2.0", - "exec-sh": "^0.2.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5", - "watch": "~0.18.0" - }, - "bin": { - "sane": "src/cli.js" - }, - "engines": { - "node": ">=0.6.0" - }, - "optionalDependencies": { - "fsevents": "^1.2.3" - } - }, - "node_modules/sane/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/sane/node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sane/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/sass-loader": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", - "dependencies": { - "clone-deep": "^2.0.1", - "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", - "neo-async": "^2.5.0", - "pify": "^3.0.0", - "semver": "^5.5.0" - }, - "engines": { - "node": ">= 6.9.0 || >= 8.9.0" - }, - "peerDependencies": { - "webpack": "^3.0.0 || ^4.0.0" - } - }, - "node_modules/sass-loader/node_modules/clone-deep": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", - "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", - "dependencies": { - "for-own": "^1.0.0", - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.0", - "shallow-clone": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sass-loader/node_modules/for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sass-loader/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sass-loader/node_modules/shallow-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", - "dependencies": { - "is-extendable": "^0.1.1", - "kind-of": "^5.0.0", - "mixin-object": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sass-loader/node_modules/shallow-clone/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/scheduler": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", - "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dependencies": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" - }, - "node_modules/selfsigned": { - "version": "1.10.14", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz", - "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==", - "dependencies": { - "node-forge": "^0.10.0" - } - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "dependencies": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/serialize-javascript": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", - "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==" - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, - "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, - "node_modules/shallow-clone": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", - "dependencies": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-clone/node_modules/kind-of": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", - "dependencies": { - "is-buffer": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-clone/node_modules/lazy-cache": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dependencies": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "node_modules/shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/sisteransi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz", - "integrity": "sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g==" - }, - "node_modules/slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/snapdragon/node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "node_modules/snapsvg": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/snapsvg/-/snapsvg-0.5.1.tgz", - "integrity": "sha1-DK9Sx5GJopB0b8RGzF6GP2vd3+M=", - "dependencies": { - "eve": "~0.5.1" - } - }, - "node_modules/snapsvg-cjs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/snapsvg-cjs/-/snapsvg-cjs-0.0.6.tgz", - "integrity": "sha1-Oy9WryVz09Nkw+1b+IhXRfTS3eE=", - "dependencies": { - "snapsvg": "0.5.1" - }, - "peerDependencies": { - "eve": "~0.5.1" - } - }, - "node_modules/sockjs": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", - "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", - "dependencies": { - "faye-websocket": "^0.10.0", - "uuid": "^3.0.1" - } - }, - "node_modules/sockjs-client": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.5.tgz", - "integrity": "sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM=", - "dependencies": { - "debug": "^2.6.6", - "eventsource": "0.1.6", - "faye-websocket": "~0.11.0", - "inherits": "^2.0.1", - "json3": "^3.3.2", - "url-parse": "^1.1.8" - } - }, - "node_modules/sockjs-client/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/sockjs-client/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/sockjs/node_modules/faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated" - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==" - }, - "node_modules/spdy": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", - "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", - "engines": [ - "node >= 0.7.0" - ], - "dependencies": { - "debug": "^2.6.8", - "handle-thing": "^1.2.5", - "http-deceiver": "^1.2.7", - "safe-buffer": "^5.0.1", - "select-hose": "^2.0.0", - "spdy-transport": "^2.0.18" - } - }, - "node_modules/spdy-transport": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.1.tgz", - "integrity": "sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==", - "dependencies": { - "debug": "^2.6.8", - "detect-node": "^2.0.3", - "hpack.js": "^2.1.6", - "obuf": "^1.1.1", - "readable-stream": "^2.2.9", - "safe-buffer": "^5.0.1", - "wbuf": "^1.7.2" - } - }, - "node_modules/spdy-transport/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/spdy-transport/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/spdy/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/spdy/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dependencies": { - "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" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ssri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", - "dependencies": { - "figgy-pudding": "^3.5.1" - } - }, - "node_modules/stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "node_modules/stack-utils": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", - "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "engines": { - "node": ">=8" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/static-extend/node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dependencies": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "node_modules/stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "dependencies": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "node_modules/stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "dependencies": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "node_modules/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==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dependencies": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "dependencies": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-comments": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", - "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", - "dependencies": { - "babel-extract-comments": "^1.0.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/style-loader": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.0.tgz", - "integrity": "sha512-uCcN7XWHkqwGVt7skpInW6IGO1tG6ReyFQ1Cseh0VcN6VdcFQi62aG/2F3Y9ueA8x4IVlfaSUxpmQXQD9QrEuQ==", - "dependencies": { - "loader-utils": "^1.1.0", - "schema-utils": "^0.4.5" - }, - "engines": { - "node": ">= 0.12.0" - } - }, - "node_modules/style-loader/node_modules/schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", - "dependencies": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "dependencies": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/stylehacks/node_modules/picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "node_modules/stylehacks/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/stylehacks/node_modules/postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "dependencies": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/stylehacks/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", - "dependencies": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/svgo/node_modules/css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "node_modules/svgo/node_modules/css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/svgo/node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/svgo/node_modules/domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/svgo/node_modules/domutils/node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - }, - "node_modules/svgo/node_modules/nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "dependencies": { - "boolbase": "~1.0.0" - } - }, - "node_modules/svgo/node_modules/util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/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==" - }, - "node_modules/table": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", - "dependencies": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", - "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", - "dependencies": { - "commander": "^2.19.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.10" - }, - "bin": { - "terser": "bin/uglifyjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz", - "integrity": "sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==", - "dependencies": { - "cacache": "^11.0.2", - "find-cache-dir": "^2.0.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "terser": "^3.8.1", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "engines": { - "node": ">= 6.9.0 <7.0.0 || >= 8.9.0" - }, - "peerDependencies": { - "webpack": "^4.3.0" - } - }, - "node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser-webpack-plugin/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/terser/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.3.tgz", - "integrity": "sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==", - "dependencies": { - "arrify": "^1.0.1", - "micromatch": "^2.3.11", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" - } - }, - "node_modules/test-exclude/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude/node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/test-exclude/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "node_modules/throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=" - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "node_modules/timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "dependencies": { - "setimmediate": "^1.0.4" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" - }, - "node_modules/to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/topo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", - "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", - "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", - "dependencies": { - "hoek": "4.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "deprecated": "support for ECMAScript is superseded by `uglify-js` as of v3.13.0", - "dependencies": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/uglify-es/node_modules/commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==" - }, - "node_modules/uglify-es/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", - "dependencies": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/uglify-js/node_modules/commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" - }, - "node_modules/uglify-js/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglifyjs-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", - "dependencies": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.5", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "engines": { - "node": ">= 4.8 < 5.0.0 || >= 5.10" - }, - "peerDependencies": { - "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/cacache": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", - "dependencies": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", - "y18n": "^4.0.0" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", - "dependencies": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^2.0.1", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", - "dependencies": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/ssri": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", - "dependencies": { - "safe-buffer": "^5.1.1" - } - }, - "node_modules/uglifyjs-webpack-plugin/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "engines": { - "node": ">=4" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" - }, - "node_modules/uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" - }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated" - }, - "node_modules/url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dependencies": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, - "node_modules/url-loader": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz", - "integrity": "sha512-vugEeXjyYFBCUOpX+ZuaunbK3QXMKaQ3zUnRfIpRBlGkY7QizCnzyyn2ASfcxsvyU3ef+CJppVywnl3Kgf13Gg==", - "dependencies": { - "loader-utils": "^1.1.0", - "mime": "^2.0.3", - "schema-utils": "^1.0.0" - }, - "engines": { - "node": ">= 6.9.0 < 7.0.0 || >= 8.9.0" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.6.tgz", - "integrity": "sha512-xj3QdUJ1DttD1LeSfvJlU1eiF1RvBSBfUu8GplFGdUzSO28y5yUtEl7wb//PI4Af6qh0o/K8545vUmucRrfWsw==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/url/node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", - "hasInstallScript": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/util.promisify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.1.tgz", - "integrity": "sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "for-each": "^0.3.3", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/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=" - }, - "node_modules/vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, - "node_modules/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==", - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/watch": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", - "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", - "dependencies": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - }, - "bin": { - "watch": "cli.js" - }, - "engines": { - "node": ">=0.1.95" - } - }, - "node_modules/watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", - "dependencies": { - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - }, - "optionalDependencies": { - "chokidar": "^3.4.1", - "watchpack-chokidar2": "^2.0.1" - } - }, - "node_modules/watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", - "optional": true, - "dependencies": { - "chokidar": "^2.1.8" - } - }, - "node_modules/watchpack-chokidar2/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "optional": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", - "optional": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/watchpack-chokidar2/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "optional": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "optional": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "optional": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "optional": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "optional": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "optional": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "optional": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "optional": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "optional": true, - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "optional": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "optional": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "optional": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "optional": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "optional": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "optional": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "optional": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "optional": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/micromatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "optional": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/micromatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "optional": true - }, - "node_modules/watchpack-chokidar2/node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/watchpack-chokidar2/node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "optional": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, - "node_modules/webpack": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.19.1.tgz", - "integrity": "sha512-j7Q/5QqZRqIFXJvC0E59ipLV5Hf6lAnS3ezC3I4HMUybwEDikQBVad5d+IpPtmaQPQArvgUZLXIN6lWijHBn4g==", - "dependencies": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-module-context": "1.7.6", - "@webassemblyjs/wasm-edit": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6", - "acorn": "^5.6.2", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", - "tapable": "^1.1.0", - "uglifyjs-webpack-plugin": "^1.2.4", - "watchpack": "^1.5.0", - "webpack-sources": "^1.2.0" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/webpack-dev-middleware": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz", - "integrity": "sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==", - "dependencies": { - "memory-fs": "~0.4.1", - "mime": "^2.3.1", - "range-parser": "^1.0.3", - "webpack-log": "^2.0.0" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } - }, - "node_modules/webpack-dev-server": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.1.9.tgz", - "integrity": "sha512-fqPkuNalLuc/hRC2QMkVYJkgNmRvxZQo7ykA2e1XRg/tMJm3qY7ZaD6d89/Fqjxtj9bOrn5wZzLD2n84lJdvWg==", - "dependencies": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.0.0", - "compression": "^1.5.2", - "connect-history-api-fallback": "^1.3.0", - "debug": "^3.1.0", - "del": "^3.0.0", - "express": "^4.16.2", - "html-entities": "^1.2.0", - "http-proxy-middleware": "~0.18.0", - "import-local": "^2.0.0", - "internal-ip": "^3.0.1", - "ip": "^1.1.5", - "killable": "^1.0.0", - "loglevel": "^1.4.1", - "opn": "^5.1.0", - "portfinder": "^1.0.9", - "schema-utils": "^1.0.0", - "selfsigned": "^1.9.1", - "serve-index": "^1.7.2", - "sockjs": "0.3.19", - "sockjs-client": "1.1.5", - "spdy": "^3.4.1", - "strip-ansi": "^3.0.0", - "supports-color": "^5.1.0", - "webpack-dev-middleware": "3.4.0", - "webpack-log": "^2.0.0", - "yargs": "12.0.2" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" - }, - "engines": { - "node": ">= 6.11.5" - }, - "peerDependencies": { - "webpack": "^4.0.0" - } - }, - "node_modules/webpack-dev-server/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-dev-server/node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/webpack-dev-server/node_modules/decamelize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", - "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", - "dependencies": { - "xregexp": "4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/webpack-dev-server/node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/webpack-dev-server/node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - }, - "engines": { - "node": ">= 4.0" - } - }, - "node_modules/webpack-dev-server/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "node_modules/webpack-dev-server/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dependencies": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/micromatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/micromatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/micromatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/webpack-dev-server/node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webpack-dev-server/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dependencies": { - "find-up": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/webpack-dev-server/node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/webpack-dev-server/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack-dev-server/node_modules/yargs": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", - "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", - "dependencies": { - "cliui": "^4.0.0", - "decamelize": "^2.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^10.1.0" - } - }, - "node_modules/webpack-dev-server/node_modules/yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dependencies": { - "camelcase": "^4.1.0" - } - }, - "node_modules/webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "dependencies": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/webpack-manifest-plugin": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.0.4.tgz", - "integrity": "sha512-nejhOHexXDBKQOj/5v5IZSfCeTO3x1Dt1RZEcGfBSul891X/eLIcIVH31gwxPDdsi2Z8LKKFGpM4w9+oTBOSCg==", - "dependencies": { - "fs-extra": "^7.0.0", - "lodash": ">=3.5 <5", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=6.11.5" - }, - "peerDependencies": { - "webpack": "2 || 3 || 4" - } - }, - "node_modules/webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "dependencies": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - } - }, - "node_modules/webpack-sources/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/webpack/node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/webpack/node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/expand-brackets/node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/expand-brackets/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webpack/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", - "dependencies": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/websocket": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", - "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", - "dependencies": { - "bufferutil": "^4.0.1", - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "typedarray-to-buffer": "^3.1.5", - "utf-8-validate": "^5.0.2", - "yaeti": "^0.0.6" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/websocket/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/whatwg-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", - "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", - "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "node_modules/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==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - }, - "node_modules/workbox-background-sync": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-3.6.3.tgz", - "integrity": "sha512-ypLo0B6dces4gSpaslmDg5wuoUWrHHVJfFWwl1udvSylLdXvnrfhFfriCS42SNEe5lsZtcNZF27W/SMzBlva7Q==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-broadcast-cache-update": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.6.3.tgz", - "integrity": "sha512-pJl4lbClQcvp0SyTiEw0zLSsVYE1RDlCPtpKnpMjxFtu8lCFTAEuVyzxp9w7GF4/b3P4h5nyQ+q7V9mIR7YzGg==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-build": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-3.6.3.tgz", - "integrity": "sha512-w0clZ/pVjL8VXy6GfthefxpEXs0T8uiRuopZSFVQ8ovfbH6c6kUpEh6DcYwm/Y6dyWPiCucdyAZotgjz+nRz8g==", - "dependencies": { - "babel-runtime": "^6.26.0", - "common-tags": "^1.4.0", - "fs-extra": "^4.0.2", - "glob": "^7.1.2", - "joi": "^11.1.1", - "lodash.template": "^4.4.0", - "pretty-bytes": "^4.0.2", - "stringify-object": "^3.2.2", - "strip-comments": "^1.0.2", - "workbox-background-sync": "^3.6.3", - "workbox-broadcast-cache-update": "^3.6.3", - "workbox-cache-expiration": "^3.6.3", - "workbox-cacheable-response": "^3.6.3", - "workbox-core": "^3.6.3", - "workbox-google-analytics": "^3.6.3", - "workbox-navigation-preload": "^3.6.3", - "workbox-precaching": "^3.6.3", - "workbox-range-requests": "^3.6.3", - "workbox-routing": "^3.6.3", - "workbox-strategies": "^3.6.3", - "workbox-streams": "^3.6.3", - "workbox-sw": "^3.6.3" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/workbox-build/node_modules/fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "node_modules/workbox-cache-expiration": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-cache-expiration/-/workbox-cache-expiration-3.6.3.tgz", - "integrity": "sha512-+ECNph/6doYx89oopO/UolYdDmQtGUgo8KCgluwBF/RieyA1ZOFKfrSiNjztxOrGJoyBB7raTIOlEEwZ1LaHoA==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-cacheable-response": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-3.6.3.tgz", - "integrity": "sha512-QpmbGA9SLcA7fklBLm06C4zFg577Dt8u3QgLM0eMnnbaVv3rhm4vbmDpBkyTqvgK/Ly8MBDQzlXDtUCswQwqqg==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-core": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-3.6.3.tgz", - "integrity": "sha512-cx9cx0nscPkIWs8Pt98HGrS9/aORuUcSkWjG25GqNWdvD/pSe7/5Oh3BKs0fC+rUshCiyLbxW54q0hA+GqZeSQ==" - }, - "node_modules/workbox-google-analytics": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-3.6.3.tgz", - "integrity": "sha512-RQBUo/6SXtIaQTRFj4RQZ9e1gAl7D8oS5S+Hi173Kk70/BgJjzPwXpC5A249Jv5YfkCOLMQCeF9A27BiD0b0ig==", - "dependencies": { - "workbox-background-sync": "^3.6.3", - "workbox-core": "^3.6.3", - "workbox-routing": "^3.6.3", - "workbox-strategies": "^3.6.3" - } - }, - "node_modules/workbox-navigation-preload": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-3.6.3.tgz", - "integrity": "sha512-dd26xTX16DUu0i+MhqZK/jQXgfIitu0yATM4jhRXEmpMqQ4MxEeNvl2CgjDMOHBnCVMax+CFZQWwxMx/X/PqCw==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-precaching": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-3.6.3.tgz", - "integrity": "sha512-aBqT66BuMFviPTW6IpccZZHzpA8xzvZU2OM1AdhmSlYDXOJyb1+Z6blVD7z2Q8VNtV1UVwQIdImIX+hH3C3PIw==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-range-requests": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-3.6.3.tgz", - "integrity": "sha512-R+yLWQy7D9aRF9yJ3QzwYnGFnGDhMUij4jVBUVtkl67oaVoP1ymZ81AfCmfZro2kpPRI+vmNMfxxW531cqdx8A==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-routing": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-3.6.3.tgz", - "integrity": "sha512-bX20i95OKXXQovXhFOViOK63HYmXvsIwZXKWbSpVeKToxMrp0G/6LZXnhg82ijj/S5yhKNRf9LeGDzaqxzAwMQ==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-strategies": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-3.6.3.tgz", - "integrity": "sha512-Pg5eulqeKet2y8j73Yw6xTgLdElktcWExGkzDVCGqfV9JCvnGuEpz5eVsCIK70+k4oJcBCin9qEg3g3CwEIH3g==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-streams": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-3.6.3.tgz", - "integrity": "sha512-rqDuS4duj+3aZUYI1LsrD2t9hHOjwPqnUIfrXSOxSVjVn83W2MisDF2Bj+dFUZv4GalL9xqErcFW++9gH+Z27w==", - "dependencies": { - "workbox-core": "^3.6.3" - } - }, - "node_modules/workbox-sw": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-3.6.3.tgz", - "integrity": "sha512-IQOUi+RLhvYCiv80RP23KBW/NTtIvzvjex28B8NW1jOm+iV4VIu3VXKXTA6er5/wjjuhmtB28qEAUqADLAyOSg==" - }, - "node_modules/workbox-webpack-plugin": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-3.6.2.tgz", - "integrity": "sha512-FGSkcaiMDM41uTGkYf7O6hf2W7UvkNc+iUIltfGiRp+qeQfXKOOh5fJCz+a6AFkeuGELSSYROsQRuOqX8LytcQ==", - "dependencies": { - "babel-runtime": "^6.26.0", - "json-stable-stringify": "^1.0.1", - "workbox-build": "^3.6.2" - }, - "engines": { - "node": ">=4.0.0" - }, - "peerDependencies": { - "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" - } - }, - "node_modules/worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "dependencies": { - "errno": "~0.1.7" - } - }, - "node_modules/wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" - }, - "node_modules/xregexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", - "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "node_modules/yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", - "engines": { - "node": ">=0.10.32" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/yargs": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", - "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", - "dependencies": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - } - }, - "node_modules/yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "dependencies": { - "camelcase": "^4.1.0" - } - }, - "node_modules/yargs-parser/node_modules/camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "engines": { - "node": ">=4" - } - }, - "node_modules/yargs/node_modules/y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "requires": { - "@babel/highlight": "^7.16.7" - } - }, - "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==" - }, - "@babel/core": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.0.tgz", - "integrity": "sha512-9EWmD0cQAbcXSc+31RIoYgEHx3KQ2CCSMDBhnXrShWvo45TMw+3/55KVxlhkG53kw9tl87DqINgHDgFVhZJV/Q==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.0.0", - "@babel/helpers": "^7.1.0", - "@babel/parser": "^7.1.0", - "@babel/template": "^7.1.0", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.0.0", - "convert-source-map": "^1.1.0", - "debug": "^3.1.0", - "json5": "^0.5.0", - "lodash": "^4.17.10", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - } - }, - "@babel/generator": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.0.tgz", - "integrity": "sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==", - "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.17.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.1.tgz", - "integrity": "sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz", - "integrity": "sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - } - }, - "@babel/helper-define-map": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.16.7.tgz", - "integrity": "sha512-SoIOh18NdeBBQjiLF1H32jpDLkApTbUWwEXmqaxn1KEm7aqry4reaghMdCdkbdloVmMwUxM/uCcTmHWj9zJbxQ==", - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", - "requires": { - "@babel/helper-get-function-arity": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", - "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==" - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" - }, - "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" - }, - "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" - } - }, - "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.0.tgz", - "integrity": "sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==" - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz", - "integrity": "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz", - "integrity": "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.16.7" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz", - "integrity": "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz", - "integrity": "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz", - "integrity": "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz", - "integrity": "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz", - "integrity": "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz", - "integrity": "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz", - "integrity": "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==", - "requires": { - "@babel/compat-data": "^7.16.4", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.16.7" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz", - "integrity": "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz", - "integrity": "sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==", - "requires": { - "@babel/helper-create-class-features-plugin": "^7.16.10", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz", - "integrity": "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz", - "integrity": "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-flow": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz", - "integrity": "sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", - "integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz", - "integrity": "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz", - "integrity": "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz", - "integrity": "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz", - "integrity": "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz", - "integrity": "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz", - "integrity": "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-flow-strip-types": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.0.0.tgz", - "integrity": "sha512-WhXUNb4It5a19RsgKKbQPrjmy4yWOY1KynpEbNw7bnd1QTcrT/EIl3MJvnGgpgvrKyKbqX7nUNOJfkpLOnoDKA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-flow": "^7.0.0" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz", - "integrity": "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz", - "integrity": "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz", - "integrity": "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", - "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz", - "integrity": "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==", - "requires": { - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz", - "integrity": "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz", - "integrity": "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.16.7.tgz", - "integrity": "sha512-lF+cfsyTgwWkcw715J88JhMYJ5GpysYNLhLP1PkvkhTRN7B3e74R/1KsDxFxhRpSn0UUD3IWM4GvdBR2PEbbQQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", - "integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-jsx": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", - "integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/plugin-transform-react-jsx-development": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", - "integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", - "requires": { - "@babel/plugin-transform-react-jsx": "^7.16.7" - } - }, - "@babel/plugin-transform-react-jsx-self": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.16.7.tgz", - "integrity": "sha512-oe5VuWs7J9ilH3BCCApGoYjHoSO48vkjX2CbA5bFVhIuO2HKxA3vyF7rleA4o6/4rTDbk6r8hBW7Ul8E+UZrpA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-jsx-source": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.16.7.tgz", - "integrity": "sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-react-pure-annotations": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", - "integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", - "requires": { - "regenerator-transform": "^0.14.2" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz", - "integrity": "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-runtime": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.1.0.tgz", - "integrity": "sha512-WFLMgzu5DLQEah0lKTJzYb14vd6UiES7PTnXcvrPZ1VrwFeJ+mTbvr65fFAsXYMt2bIoOoC0jk76zY1S7HZjUg==", - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "resolve": "^1.8.1", - "semver": "^5.5.1" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz", - "integrity": "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz", - "integrity": "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz", - "integrity": "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/preset-react": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", - "integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-transform-react-display-name": "^7.16.7", - "@babel/plugin-transform-react-jsx": "^7.16.7", - "@babel/plugin-transform-react-jsx-development": "^7.16.7", - "@babel/plugin-transform-react-pure-annotations": "^7.16.7" - } - }, - "@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/traverse": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.0.tgz", - "integrity": "sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==", - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.0", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.0", - "@babel/types": "^7.17.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, - "@csstools/convert-colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz", - "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==" - }, - "@mapbox/tiny-sdf": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.4.tgz", - "integrity": "sha512-CBtL2rhZiYmdIryksp0zh4Mmx54iClYfNb0mpYeHrZnq4z84lVjre7LBWGPEjWspEn6AiF0lxC1HaZDye89m3g==" - }, - "@mrmlnc/readdir-enhanced": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "requires": { - "call-me-maybe": "^1.0.1", - "glob-to-regexp": "^0.3.0" - } - }, - "@nodelib/fs.stat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" - }, - "@svgr/core": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@svgr/core/-/core-2.4.1.tgz", - "integrity": "sha512-2i1cUbjpKt1KcIP05e10vkmu9Aedp32EFqVcSQ08onbB8lVxJqMPci3Hr54aI14S9cLg4JdcpO0D35HHUtT8oQ==", - "requires": { - "camelcase": "^5.0.0", - "cosmiconfig": "^5.0.6", - "h2x-core": "^1.1.0", - "h2x-plugin-jsx": "^1.1.0", - "merge-deep": "^3.0.2", - "prettier": "^1.14.2", - "svgo": "^1.0.5" - } - }, - "@svgr/webpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-2.4.1.tgz", - "integrity": "sha512-sMHYq0zbMtSHcc9kVfkYI2zrl88u4mKGyQLgKt7r+ul5nITcncm/EPBhzEUrJY5izdlaU6EvyH8zOhZnfaSmOA==", - "requires": { - "@babel/core": "^7.0.1", - "@babel/plugin-transform-react-constant-elements": "^7.0.0", - "@babel/preset-env": "^7.0.0", - "@babel/preset-react": "^7.0.0", - "@svgr/core": "^2.4.1", - "loader-utils": "^1.1.0" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==" - }, - "@types/q": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", - "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" - }, - "@types/tapable": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.2.tgz", - "integrity": "sha512-42zEJkBpNfMEAvWR5WlwtTH22oDzcMjFsL9gDGExwF8X8WvAiw7Vwop7hPw03QT8TKfec83LwbHj6SvpqM4ELQ==" - }, - "@webassemblyjs/ast": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.6.tgz", - "integrity": "sha512-8nkZS48EVsMUU0v6F1LCIOw4RYWLm2plMtbhFTjNgeXmsTNLuU3xTRtnljt9BFQB+iPbLRobkNrCWftWnNC7wQ==", - "requires": { - "@webassemblyjs/helper-module-context": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/wast-parser": "1.7.6", - "mamacro": "^0.0.3" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz", - "integrity": "sha512-VBOZvaOyBSkPZdIt5VBMg3vPWxouuM13dPXGWI1cBh3oFLNcFJ8s9YA7S9l4mPI7+Q950QqOmqj06oa83hNWBA==" - }, - "@webassemblyjs/helper-api-error": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz", - "integrity": "sha512-SCzhcQWHXfrfMSKcj8zHg1/kL9kb3aa5TN4plc/EREOs5Xop0ci5bdVBApbk2yfVi8aL+Ly4Qpp3/TRAUInjrg==" - }, - "@webassemblyjs/helper-buffer": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz", - "integrity": "sha512-1/gW5NaGsEOZ02fjnFiU8/OEEXU1uVbv2um0pQ9YVL3IHSkyk6xOwokzyqqO1qDZQUAllb+V8irtClPWntbVqw==" - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz", - "integrity": "sha512-+suMJOkSn9+vEvDvgyWyrJo5vJsWSDXZmJAjtoUq4zS4eqHyXImpktvHOZwXp1XQjO5H+YQwsBgqTQEc0J/5zg==", - "requires": { - "@webassemblyjs/wast-printer": "1.7.6" - } - }, - "@webassemblyjs/helper-fsm": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz", - "integrity": "sha512-HCS6KN3wgxUihGBW7WFzEC/o8Eyvk0d56uazusnxXthDPnkWiMv+kGi9xXswL2cvfYfeK5yiM17z2K5BVlwypw==" - }, - "@webassemblyjs/helper-module-context": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz", - "integrity": "sha512-e8/6GbY7OjLM+6OsN7f2krC2qYVNaSr0B0oe4lWdmq5sL++8dYDD1TFbD1TdAdWMRTYNr/Qq7ovXWzia2EbSjw==", - "requires": { - "mamacro": "^0.0.3" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz", - "integrity": "sha512-PzYFCb7RjjSdAOljyvLWVqd6adAOabJW+8yRT+NWhXuf1nNZWH+igFZCUK9k7Cx7CsBbzIfXjJc7u56zZgFj9Q==" - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz", - "integrity": "sha512-3GS628ppDPSuwcYlQ7cDCGr4W2n9c4hLzvnRKeuz+lGsJSmc/ADVoYpm1ts2vlB1tGHkjtQMni+yu8mHoMlKlA==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz", - "integrity": "sha512-V4cIp0ruyw+hawUHwQLn6o2mFEw4t50tk530oKsYXQhEzKR+xNGDxs/SFFuyTO7X3NzEu4usA3w5jzhl2RYyzQ==", - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.6.tgz", - "integrity": "sha512-ojdlG8WpM394lBow4ncTGJoIVZ4aAtNOWHhfAM7m7zprmkVcKK+2kK5YJ9Bmj6/ketTtOn7wGSHCtMt+LzqgYQ==", - "requires": { - "@xtuc/long": "4.2.1" - } - }, - "@webassemblyjs/utf8": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.6.tgz", - "integrity": "sha512-oId+tLxQ+AeDC34ELRYNSqJRaScB0TClUU6KQfpB8rNT6oelYlz8axsPhf6yPTg7PBJ/Z5WcXmUYiHEWgbbHJw==" - }, - "@webassemblyjs/wasm-edit": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz", - "integrity": "sha512-pTNjLO3o41v/Vz9VFLl+I3YLImpCSpodFW77pNoH4agn5I6GgSxXHXtvWDTvYJFty0jSeXZWLEmbaSIRUDlekg==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/helper-wasm-section": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6", - "@webassemblyjs/wasm-opt": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6", - "@webassemblyjs/wast-printer": "1.7.6" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz", - "integrity": "sha512-mQvFJVumtmRKEUXMohwn8nSrtjJJl6oXwF3FotC5t6e2hlKMh8sIaW03Sck2MDzw9xPogZD7tdP5kjPlbH9EcQ==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/ieee754": "1.7.6", - "@webassemblyjs/leb128": "1.7.6", - "@webassemblyjs/utf8": "1.7.6" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz", - "integrity": "sha512-go44K90fSIsDwRgtHhX14VtbdDPdK2sZQtZqUcMRvTojdozj5tLI0VVJAzLCfz51NOkFXezPeVTAYFqrZ6rI8Q==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz", - "integrity": "sha512-t1T6TfwNY85pDA/HWPA8kB9xA4sp9ajlRg5W7EKikqrynTyFo+/qDzIpvdkOkOGjlS6d4n4SX59SPuIayR22Yg==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-api-error": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/ieee754": "1.7.6", - "@webassemblyjs/leb128": "1.7.6", - "@webassemblyjs/utf8": "1.7.6" - } - }, - "@webassemblyjs/wast-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz", - "integrity": "sha512-1MaWTErN0ziOsNUlLdvwS+NS1QWuI/kgJaAGAMHX8+fMJFgOJDmN/xsG4h/A1Gtf/tz5VyXQciaqHZqp2q0vfg==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/floating-point-hex-parser": "1.7.6", - "@webassemblyjs/helper-api-error": "1.7.6", - "@webassemblyjs/helper-code-frame": "1.7.6", - "@webassemblyjs/helper-fsm": "1.7.6", - "@xtuc/long": "4.2.1", - "mamacro": "^0.0.3" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz", - "integrity": "sha512-vHdHSK1tOetvDcl1IV1OdDeGNe/NDDQ+KzuZHMtqTVP1xO/tZ/IKNpj5BaGk1OYFdsDWQqb31PIwdEyPntOWRQ==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/wast-parser": "1.7.6", - "@xtuc/long": "4.2.1" - } - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" - }, - "@xtuc/long": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", - "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==" - }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - }, - "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", - "requires": { - "acorn": "^5.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" - } - } - }, - "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" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" - } - } - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==" - }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" - }, - "address": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz", - "integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg==" - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "requires": { - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==" - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "optional": true - }, - "ansi-colors": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", - "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==" - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==" - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", - "requires": { - "default-require-extensions": "^1.0.0" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "aria-query": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", - "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", - "requires": { - "ast-types-flow": "0.0.7", - "commander": "^2.11.0" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" - }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" - }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" - }, - "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", - "get-intrinsic": "^1.1.1", - "is-string": "^1.0.7" - } - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, - "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.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - } - } - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" - }, - "ast-transform": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/ast-transform/-/ast-transform-0.0.0.tgz", - "integrity": "sha1-dJRAWIh9goPhidlUYAlHvJj+AGI=", - "requires": { - "escodegen": "~1.2.0", - "esprima": "~1.0.4", - "through": "~2.3.4" - }, - "dependencies": { - "escodegen": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.2.0.tgz", - "integrity": "sha1-Cd55Z3kcyVi3+Jot220jRRrzJ+E=", - "requires": { - "esprima": "~1.0.4", - "estraverse": "~1.5.0", - "esutils": "~1.0.0", - "source-map": "~0.1.30" - } - }, - "esprima": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=" - }, - "estraverse": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz", - "integrity": "sha1-hno+jlip+EYYr7bC3bzZFrfLr3E=" - }, - "esutils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz", - "integrity": "sha1-gVHTWOIMisx/t0XnRywAJf5JZXA=" - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "ast-types": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.7.8.tgz", - "integrity": "sha1-kC0uDWDQcb3NRtwRXhgJ7RHBOKk=" - }, - "ast-types-flow": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=" - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==" - }, - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "requires": { - "lodash": "^4.17.14" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" - }, - "autoprefixer": { - "version": "9.8.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", - "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "picocolors": "^0.2.1", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "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.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" - }, - "axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "babel-core": { - "version": "7.0.0-bridge.0", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", - "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==" - }, - "babel-eslint": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-9.0.0.tgz", - "integrity": "sha512-itv1MwE3TMbY0QtNfeL7wzak1mV47Uy+n6HtSOO4Xd7rvmO+tsGQSgyOEEgo6Y2vHZKZphaoelNeSVj4vkLA1g==", - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.0.0", - "@babel/traverse": "^7.0.0", - "@babel/types": "^7.0.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "^1.0.0" - } - }, - "babel-extract-comments": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz", - "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==", - "requires": { - "babylon": "^6.18.0" - } - }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - } - } - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } - }, - "babel-jest": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", - "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", - "requires": { - "babel-plugin-istanbul": "^4.1.6", - "babel-preset-jest": "^23.2.0" - } - }, - "babel-loader": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.4.tgz", - "integrity": "sha512-fhBhNkUToJcW9nV46v8w87AJOwAJDz84c1CL57n3Stj73FANM/b9TbCUK4YhdOwEyZ+OxhYpdeZDNzSI29Firw==", - "requires": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0" - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-istanbul": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", - "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.13.0", - "find-up": "^2.1.0", - "istanbul-lib-instrument": "^1.10.1", - "test-exclude": "^4.2.1" - } - }, - "babel-plugin-jest-hoist": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz", - "integrity": "sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc=" - }, - "babel-plugin-macros": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.4.2.tgz", - "integrity": "sha512-NBVpEWN4OQ/bHnu1fyDaAaTPAjnhXCEPqr1RwqxrU7b6tZ2hypp+zX4hlNfmVGfClD5c3Sl6Hfj5TJNF5VG5aA==", - "requires": { - "cosmiconfig": "^5.0.5", - "resolve": "^1.8.1" - } - }, - "babel-plugin-named-asset-import": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.2.3.tgz", - "integrity": "sha512-9mx2Z9M4EGbutvXxoLV7aUBCY6ps3sqLFl094FeA2tFQzQffIh0XSsmwwQRxiSfpg3rnb5x/o46qRLxS/OzFTg==" - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", - "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - } - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.21.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - } - }, - "babel-plugin-syntax-object-rest-spread": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", - "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=" - }, - "babel-plugin-transform-object-rest-spread": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz", - "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=", - "requires": { - "babel-plugin-syntax-object-rest-spread": "^6.8.0", - "babel-runtime": "^6.26.0" - } - }, - "babel-plugin-transform-react-remove-prop-types": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.18.tgz", - "integrity": "sha512-azed2nHo8vmOy7EY26KH+om5oOcWRs0r1U8wOmhwta+SBMMnmJ4H6yaBZRCcHBtMeWp9AVhvBTL/lpR1kEx+Xw==" - }, - "babel-preset-jest": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz", - "integrity": "sha1-jsegOhOPABoaj7HoETZSvxpV2kY=", - "requires": { - "babel-plugin-jest-hoist": "^23.2.0", - "babel-plugin-syntax-object-rest-spread": "^6.13.0" - } - }, - "babel-preset-react-app": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-5.0.4.tgz", - "integrity": "sha512-NQ344N1BXY4ur8c7iRqj1JQvcI6tiLbNB8W2z0Vanmc6xld+EG9CYk9cfIFTPgk5RCkughimt+0uw2nd2CyevQ==", - "requires": { - "@babel/core": "7.1.0", - "@babel/plugin-proposal-class-properties": "7.1.0", - "@babel/plugin-proposal-object-rest-spread": "7.0.0", - "@babel/plugin-syntax-dynamic-import": "7.0.0", - "@babel/plugin-transform-classes": "7.1.0", - "@babel/plugin-transform-destructuring": "7.0.0", - "@babel/plugin-transform-flow-strip-types": "7.0.0", - "@babel/plugin-transform-react-constant-elements": "7.0.0", - "@babel/plugin-transform-react-display-name": "7.0.0", - "@babel/plugin-transform-runtime": "7.1.0", - "@babel/preset-env": "7.1.0", - "@babel/preset-react": "7.0.0", - "@babel/runtime": "7.0.0", - "babel-loader": "8.0.4", - "babel-plugin-dynamic-import-node": "2.2.0", - "babel-plugin-macros": "2.4.2", - "babel-plugin-transform-react-remove-prop-types": "0.4.18" - }, - "dependencies": { - "@babel/plugin-proposal-class-properties": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.1.0.tgz", - "integrity": "sha512-/PCJWN+CKt5v1xcGn4vnuu13QDoV+P7NcICP44BoonAJoPSGwVkgrXihFIQGiEjjPlUDBIw1cM7wYFLARS2/hw==", - "requires": { - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-member-expression-to-functions": "^7.0.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/plugin-syntax-class-properties": "^7.0.0" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz", - "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.0.0.tgz", - "integrity": "sha512-Gt9xNyRrCHCiyX/ZxDGOcBnlJl0I3IWicpZRC4CdC0P5a/I07Ya2OAMEBU+J7GmRFVmIetqEYRko6QYRuKOESw==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz", - "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-define-map": "^7.1.0", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-optimise-call-expression": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-replace-supers": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.0.0", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0.tgz", - "integrity": "sha512-Fr2GtF8YJSXGTyFPakPFB4ODaEKGU04bPsAllAIabwoXdFrPxL0LVXQX5dQWoxOjjgozarJcC9eWGsj0fD6Zsg==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-react-constant-elements": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.0.0.tgz", - "integrity": "sha512-z8yrW4KCVcqPYr0r9dHXe7fu3daLzn0r6TQEFoGbXahdrzEwT1d1ux+/EnFcqIHv9uPilUlnRnPIUf7GMO0ehg==", - "requires": { - "@babel/helper-annotate-as-pure": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/plugin-transform-react-display-name": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.0.0.tgz", - "integrity": "sha512-BX8xKuQTO0HzINxT6j/GiCwoJB0AOMs0HmLbEnAvcte8U8rSkNa/eSCAY+l1OA4JnCVq2jw2p6U8QQryy2fTPg==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/preset-env": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz", - "integrity": "sha512-ZLVSynfAoDHB/34A17/JCZbyrzbQj59QC1Anyueb4Bwjh373nVPq5/HMph0z+tCmcDjXDe+DlKQq9ywQuvWrQg==", - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-async-generator-functions": "^7.1.0", - "@babel/plugin-proposal-json-strings": "^7.0.0", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", - "@babel/plugin-syntax-async-generators": "^7.0.0", - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", - "@babel/plugin-transform-arrow-functions": "^7.0.0", - "@babel/plugin-transform-async-to-generator": "^7.1.0", - "@babel/plugin-transform-block-scoped-functions": "^7.0.0", - "@babel/plugin-transform-block-scoping": "^7.0.0", - "@babel/plugin-transform-classes": "^7.1.0", - "@babel/plugin-transform-computed-properties": "^7.0.0", - "@babel/plugin-transform-destructuring": "^7.0.0", - "@babel/plugin-transform-dotall-regex": "^7.0.0", - "@babel/plugin-transform-duplicate-keys": "^7.0.0", - "@babel/plugin-transform-exponentiation-operator": "^7.1.0", - "@babel/plugin-transform-for-of": "^7.0.0", - "@babel/plugin-transform-function-name": "^7.1.0", - "@babel/plugin-transform-literals": "^7.0.0", - "@babel/plugin-transform-modules-amd": "^7.1.0", - "@babel/plugin-transform-modules-commonjs": "^7.1.0", - "@babel/plugin-transform-modules-systemjs": "^7.0.0", - "@babel/plugin-transform-modules-umd": "^7.1.0", - "@babel/plugin-transform-new-target": "^7.0.0", - "@babel/plugin-transform-object-super": "^7.1.0", - "@babel/plugin-transform-parameters": "^7.1.0", - "@babel/plugin-transform-regenerator": "^7.0.0", - "@babel/plugin-transform-shorthand-properties": "^7.0.0", - "@babel/plugin-transform-spread": "^7.0.0", - "@babel/plugin-transform-sticky-regex": "^7.0.0", - "@babel/plugin-transform-template-literals": "^7.0.0", - "@babel/plugin-transform-typeof-symbol": "^7.0.0", - "@babel/plugin-transform-unicode-regex": "^7.0.0", - "browserslist": "^4.1.0", - "invariant": "^2.2.2", - "js-levenshtein": "^1.1.3", - "semver": "^5.3.0" - } - }, - "@babel/preset-react": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", - "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-transform-react-display-name": "^7.0.0", - "@babel/plugin-transform-react-jsx": "^7.0.0", - "@babel/plugin-transform-react-jsx-self": "^7.0.0", - "@babel/plugin-transform-react-jsx-source": "^7.0.0" - } - }, - "@babel/runtime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz", - "integrity": "sha512-7hGhzlcmg01CvH1EHdSPVXYX1aJ8KCEyz6I9xYIi/asDtzBPMyMhVibhM/K6g/5qnKBwjZtp10bNZIEFTRW1MA==", - "requires": { - "regenerator-runtime": "^0.12.0" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.2.0.tgz", - "integrity": "sha512-fP899ELUnTaBcIzmrW7nniyqqdYWrWuJUyPWHxFa/c7r7hS6KC8FscNfLlBNIoPSc55kYMGEEKjPjJGCLbE1qA==", - "requires": { - "object.assign": "^4.1.0" - } - }, - "regenerator-runtime": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", - "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" - } - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - }, - "dependencies": { - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "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=" - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - } - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - } - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, - "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" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - }, - "dependencies": { - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - } - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" - }, - "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" - } - }, - "bfj": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.1.tgz", - "integrity": "sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ==", - "requires": { - "bluebird": "^3.5.1", - "check-types": "^7.3.0", - "hoopy": "^0.1.2", - "tryer": "^1.0.0" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "optional": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" - }, - "bn.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", - "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" - }, - "body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", - "requires": { - "bytes": "3.1.1", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.6", - "raw-body": "2.4.2", - "type-is": "~1.6.18" - }, - "dependencies": { - "bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" - }, - "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=" - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "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" - } - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "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==" - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" - } - } - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "browserify-optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-optional/-/browserify-optional-1.0.1.tgz", - "integrity": "sha1-HhNyLP3g2F8SFnbCpyztUzoBiGk=", - "requires": { - "ast-transform": "0.0.0", - "ast-types": "^0.7.0", - "browser-resolve": "^1.8.1" - } - }, - "browserify-rsa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", - "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", - "requires": { - "bn.js": "^5.0.0", - "randombytes": "^2.0.1" - } - }, - "browserify-sign": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", - "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.3", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, - "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", - "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", - "escalade": "^3.1.1", - "node-releases": "^2.0.1", - "picocolors": "^1.0.0" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "bufferutil": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", - "integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==", - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" - }, - "cacache": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", - "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "requires": { - "callsites": "^2.0.0" - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=" - }, - "camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "requires": { - "no-case": "^2.2.0", - "upper-case": "^1.1.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==" - }, - "capture-exit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz", - "integrity": "sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28=", - "requires": { - "rsvp": "^3.3.3" - } - }, - "case-sensitive-paths-webpack-plugin": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.1.2.tgz", - "integrity": "sha512-oEZgAFfEvKtjSRCu6VgYkuGxwrWXMnQzyBmlLPP7r6PWQVtHxP5Z5N6XsuJvtoVax78am/r7lr46bwo3IVEBOg==" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" - }, - "check-types": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz", - "integrity": "sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg==" - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "optional": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "optional": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "optional": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "optional": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "optional": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "optional": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "optional": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "optional": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "optional": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "optional": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" - }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - } - } - }, - "classnames": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", - "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" - }, - "clean-css": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", - "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", - "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==" - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "clone-deep": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", - "integrity": "sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY=", - "requires": { - "for-own": "^0.1.3", - "is-plain-object": "^2.0.1", - "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", - "shallow-clone": "^0.1.2" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "coa": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", - "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", - "requires": { - "@types/q": "^1.5.1", - "chalk": "^2.4.1", - "q": "^1.1.2" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "requires": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", - "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "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" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "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=" - } - } - }, - "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" - } - }, - "confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" - }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==" - }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" - }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - }, - "core-js-compat": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.0.tgz", - "integrity": "sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==", - "requires": { - "browserslist": "^4.19.1", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" - } - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - } - }, - "create-ecdh": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", - "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.5.3" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "requires": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-browserify": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", - "requires": { - "browserify-cipher": "^1.0.0", - "browserify-sign": "^4.0.0", - "create-ecdh": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.0", - "diffie-hellman": "^5.0.0", - "inherits": "^2.0.1", - "pbkdf2": "^3.0.3", - "public-encrypt": "^4.0.0", - "randombytes": "^2.0.0", - "randomfill": "^1.0.3" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" - }, - "css-declaration-sorter": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz", - "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==", - "requires": { - "postcss": "^7.0.1", - "timsort": "^0.3.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "css-loader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-1.0.0.tgz", - "integrity": "sha512-tMXlTYf3mIMt3b0dDCOQFJiVvxbocJ5Ho577WiGPYPZcqVEO218L2iU22pDXzkTZCLDE+9AmGSUkWxeh/nZReA==", - "requires": { - "babel-code-frame": "^6.26.0", - "css-selector-tokenizer": "^0.7.0", - "icss-utils": "^2.1.0", - "loader-utils": "^1.0.2", - "lodash.camelcase": "^4.3.0", - "postcss": "^6.0.23", - "postcss-modules-extract-imports": "^1.2.0", - "postcss-modules-local-by-default": "^1.2.0", - "postcss-modules-scope": "^1.1.0", - "postcss-modules-values": "^1.3.0", - "postcss-value-parser": "^3.3.0", - "source-list-map": "^2.0.0" - } - }, - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-select-base-adapter": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", - "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" - }, - "css-selector-tokenizer": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", - "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", - "requires": { - "cssesc": "^3.0.0", - "fastparse": "^1.1.2" - } - }, - "css-tree": { - "version": "1.0.0-alpha.37", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", - "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", - "requires": { - "mdn-data": "2.0.4", - "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" - }, - "cssdb": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-3.2.1.tgz", - "integrity": "sha512-I0IS8zvxED8sQtFZnV7M+AkhWqTgp1HIyfMQJBbjdn4GgurBt7NCZaDgrWiAN2kNJN34mhF1p50aZIMQu290mA==" - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" - }, - "cssnano": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz", - "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==", - "requires": { - "cosmiconfig": "^5.0.0", - "cssnano-preset-default": "^4.0.8", - "is-resolvable": "^1.0.0", - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "cssnano-preset-default": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz", - "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==", - "requires": { - "css-declaration-sorter": "^4.0.1", - "cssnano-util-raw-cache": "^4.0.1", - "postcss": "^7.0.0", - "postcss-calc": "^7.0.1", - "postcss-colormin": "^4.0.3", - "postcss-convert-values": "^4.0.1", - "postcss-discard-comments": "^4.0.2", - "postcss-discard-duplicates": "^4.0.2", - "postcss-discard-empty": "^4.0.1", - "postcss-discard-overridden": "^4.0.1", - "postcss-merge-longhand": "^4.0.11", - "postcss-merge-rules": "^4.0.3", - "postcss-minify-font-values": "^4.0.2", - "postcss-minify-gradients": "^4.0.2", - "postcss-minify-params": "^4.0.2", - "postcss-minify-selectors": "^4.0.2", - "postcss-normalize-charset": "^4.0.1", - "postcss-normalize-display-values": "^4.0.2", - "postcss-normalize-positions": "^4.0.2", - "postcss-normalize-repeat-style": "^4.0.2", - "postcss-normalize-string": "^4.0.2", - "postcss-normalize-timing-functions": "^4.0.2", - "postcss-normalize-unicode": "^4.0.1", - "postcss-normalize-url": "^4.0.1", - "postcss-normalize-whitespace": "^4.0.2", - "postcss-ordered-values": "^4.1.2", - "postcss-reduce-initial": "^4.0.3", - "postcss-reduce-transforms": "^4.0.2", - "postcss-svgo": "^4.0.3", - "postcss-unique-selectors": "^4.0.1" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "cssnano-util-get-arguments": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz", - "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=" - }, - "cssnano-util-get-match": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz", - "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=" - }, - "cssnano-util-raw-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz", - "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "cssnano-util-same-parent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz", - "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==" - }, - "csso": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", - "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", - "requires": { - "css-tree": "^1.1.2" - }, - "dependencies": { - "css-tree": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", - "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", - "requires": { - "mdn-data": "2.0.14", - "source-map": "^0.6.1" - } - }, - "mdn-data": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", - "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==" - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "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==" - } - } - }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" - }, - "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": "3.0.1", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.1.tgz", - "integrity": "sha512-Ds554NeT5Gennfoo9KN50Vh6tpgtvYEwraYjejXnyTpu1C7oXKxdFk75REooENHE8ndTVOJuv+BEs4/J/xcozw==", - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^10.0.0" - } - }, - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "requires": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" - } - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" - }, - "default-gateway": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.2.tgz", - "integrity": "sha512-lAc4i9QJR0YHSDFdzeBQKfZ1SRDG3hsJNEkrpcZa8QhBfidLAilT60BDEIVUUGqosFp425KOgB3uYqcnQrWafQ==", - "requires": { - "execa": "^0.10.0", - "ip-regex": "^2.1.0" - } - }, - "default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", - "requires": { - "strip-bom": "^2.0.0" - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "del": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", - "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", - "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" - }, - "dependencies": { - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "^2.0.0" - } - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" - }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" - }, - "detect-port-alt": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", - "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", - "requires": { - "address": "^1.0.1", - "debug": "^2.6.0" - }, - "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=" - } - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "dir-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", - "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", - "requires": { - "path-type": "^3.0.0" - } - }, - "distance-to-line-segment": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/distance-to-line-segment/-/distance-to-line-segment-0.2.0.tgz", - "integrity": "sha1-5FQnu4Ng61mob/2YFKdXjdLD1nk=" - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" - }, - "dns-packet": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", - "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-converter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", - "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", - "requires": { - "utila": "~0.4" - } - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" - }, - "domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "requires": { - "webidl-conversions": "^7.0.0" - } - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "requires": { - "is-obj": "^2.0.0" - }, - "dependencies": { - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" - } - } - }, - "dotenv": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.0.0.tgz", - "integrity": "sha512-FlWbnhgjtwD+uNLUGHbMykMOYQaTivdHEmYwAKFjn6GKe/CqY0fNae93ZHTd20snh9ZLr8mTzIL9m0APQ1pjQg==" - }, - "dotenv-expand": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-4.2.0.tgz", - "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=" - }, - "draco3d": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.0.tgz", - "integrity": "sha512-8ESjH7o5xju1nfSvcS2A9vIbwSRQ3yYY0Yv7SFhNszsq4FlN4LGZuxNc3YfAPcg0AddaK0dE5AES3w1JoGeViA==" - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "earcut": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", - "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==" - }, - "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" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "electron-to-chromium": { - "version": "1.4.68", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.68.tgz", - "integrity": "sha512-cId+QwWrV8R1UawO6b9BR1hnkJ4EJPCPAr4h315vliHUtVUJDk39Sg1PMNnaWKfj5x+93ssjeJ9LKL6r8LaMiA==" - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "emoji-regex": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz", - "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==" - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", - "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.5.0", - "tapable": "^1.0.0" - }, - "dependencies": { - "memory-fs": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", - "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - } - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==" - }, - "errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "requires": { - "prr": "~1.0.1" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - }, - "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 - } - } - }, - "eslint": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.6.0.tgz", - "integrity": "sha512-/eVYs9VVVboX286mBK7bbKnO1yamUy2UCRjiY6MryhQL2PaaXCExsCQ2aO83OeYRhU2eCU/FMFP+tVMoOrzNrA==", - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.12.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^2.0.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^4.0.3", - "text-table": "^0.2.0" - }, - "dependencies": { - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - } - } - }, - "eslint-config-react-app": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-3.0.8.tgz", - "integrity": "sha512-Ovi6Bva67OjXrom9Y/SLJRkrGqKhMAL0XCH8BizPhjEVEhYczl2ZKiNZI2CuqO5/CJwAfMwRXAVGY0KToWr1aA==", - "requires": { - "confusing-browser-globals": "^1.0.6" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", - "requires": { - "debug": "^3.2.7", - "resolve": "^1.20.0" - }, - "dependencies": { - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "eslint-loader": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-2.1.1.tgz", - "integrity": "sha512-1GrJFfSevQdYpoDzx8mEE2TDWsb/zmFuY09l6hURg1AeFIKQOvZ+vH0UPjzmd1CZIbfTV5HUkMeBmFiDBkgIsQ==", - "requires": { - "loader-fs-cache": "^1.0.0", - "loader-utils": "^1.0.2", - "object-assign": "^4.0.1", - "object-hash": "^1.1.4", - "rimraf": "^2.6.1" - } - }, - "eslint-module-utils": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz", - "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==", - "requires": { - "debug": "^3.2.7", - "find-up": "^2.1.0" - } - }, - "eslint-plugin-flowtype": { - "version": "2.50.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.50.1.tgz", - "integrity": "sha512-9kRxF9hfM/O6WGZcZPszOVPd2W0TLHBtceulLTsGfwMPtiCCLnCW0ssRiOOiXyqrCA20pm1iXdXm7gQeN306zQ==", - "requires": { - "lodash": "^4.17.10" - } - }, - "eslint-plugin-import": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", - "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", - "requires": { - "contains-path": "^0.1.0", - "debug": "^2.6.8", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.2.0", - "has": "^1.0.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0", - "resolve": "^1.6.0" - }, - "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" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "eslint-plugin-jsx-a11y": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.1.1.tgz", - "integrity": "sha512-JsxNKqa3TwmPypeXNnI75FntkUktGzI1wSa1LgNZdSOMI+B4sxnr1lSF8m8lPiz4mKiC+14ysZQM4scewUrP7A==", - "requires": { - "aria-query": "^3.0.0", - "array-includes": "^3.0.3", - "ast-types-flow": "^0.0.7", - "axobject-query": "^2.0.1", - "damerau-levenshtein": "^1.0.4", - "emoji-regex": "^6.5.1", - "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1" - } - }, - "eslint-plugin-react": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", - "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", - "requires": { - "array-includes": "^3.0.3", - "doctrine": "^2.1.0", - "has": "^1.0.3", - "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.2" - } - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" - }, - "espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", - "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" - } - } - }, - "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==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "eve": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/eve/-/eve-0.5.4.tgz", - "integrity": "sha1-Z9CAuXJSkdfjieNMJoYN2X8d66o=" - }, - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "eventsource": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", - "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", - "requires": { - "original": ">=0.0.5" - } - }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "exec-sh": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", - "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", - "requires": { - "merge": "^1.2.0" - } - }, - "execa": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", - "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "requires": { - "fill-range": "^2.1.0" - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "expect": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz", - "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==", - "requires": { - "ansi-styles": "^3.2.0", - "jest-diff": "^23.6.0", - "jest-get-type": "^22.1.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "jest-diff": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", - "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", - "requires": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - } - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "express": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", - "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.4.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.9.6", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", - "setprototypeof": "1.2.0", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "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=" - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", - "requires": { - "type": "^2.5.0" - }, - "dependencies": { - "type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==" - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-glob": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", - "requires": { - "@mrmlnc/readdir-enhanced": "^2.2.1", - "@nodelib/fs.stat": "^1.1.2", - "glob-parent": "^3.1.0", - "is-glob": "^4.0.0", - "merge2": "^1.2.3", - "micromatch": "^3.1.10" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "fastparse": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", - "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" - }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", - "requires": { - "bser": "2.1.1" - } - }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" - } - }, - "file-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz", - "integrity": "sha512-YCsBfd1ZGCyonOKLxPiKPdu+8ld9HAaMEvJewzz+b2eTF7uL5Zm/HdBF6FjCrpCMRq25Mi0U1gl4pwn2TlH7hQ==", - "requires": { - "loader-utils": "^1.0.2", - "schema-utils": "^1.0.0" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "optional": true - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" - }, - "fileset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", - "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", - "requires": { - "glob": "^7.0.3", - "minimatch": "^3.0.3" - } - }, - "filesize": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", - "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==" - }, - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "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=" - } - } - }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", - "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", - "requires": { - "circular-json": "^0.3.1", - "graceful-fs": "^4.1.2", - "rimraf": "~2.6.2", - "write": "^0.2.1" - }, - "dependencies": { - "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" - } - } - } - }, - "flatten": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz", - "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==" - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "follow-redirects": { - "version": "1.14.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", - "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==" - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "requires": { - "is-callable": "^1.1.3" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "requires": { - "for-in": "^1.0.1" - } - }, - "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": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-extra": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.0.tgz", - "integrity": "sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", - "optional": true, - "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "debug": { - "version": "2.6.9", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.5.1", - "bundled": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "optional": true, - "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" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.21", - "bundled": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "optional": true - }, - "minipass": { - "version": "2.2.4", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.1.0", - "bundled": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "needle": { - "version": "2.2.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "^2.1.2", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.10.0", - "bundled": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.3", - "bundled": true, - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "bundled": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.7", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "optional": true, - "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" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "optional": true - }, - "semver": { - "version": "5.5.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "4.4.1", - "bundled": true, - "optional": true, - "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "yallist": { - "version": "3.0.2", - "bundled": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-own-enumerable-property-symbols": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", - "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" - }, - "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" - } - }, - "gl-matrix": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.3.tgz", - "integrity": "sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==" - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "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" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "requires": { - "is-glob": "^2.0.0" - } - }, - "glob-to-regexp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" - }, - "globby": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", - "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "fast-glob": "^2.0.2", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - }, - "dependencies": { - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" - } - } - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" - }, - "gzip-size": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", - "integrity": "sha512-5iI7omclyqrnWw4XbXAmGhPsABkSIDQonv2K0h61lybgofWa6iZyvrI3r2zsJH4P8Nb64fFVzlvfhs0g7BBxAA==", - "requires": { - "duplexer": "^0.1.1", - "pify": "^3.0.0" - } - }, - "h2x-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/h2x-core/-/h2x-core-1.1.1.tgz", - "integrity": "sha512-LdXe4Irs731knLtHgLyFrnJCumfiqXXQwKN1IMUhi37li29PLfLbMDvfK7Rk4wmgHLKP+sIITT1mcJV4QsC3nw==", - "requires": { - "h2x-generate": "^1.1.0", - "h2x-parse": "^1.1.1", - "h2x-traverse": "^1.1.0" - } - }, - "h2x-generate": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/h2x-generate/-/h2x-generate-1.1.0.tgz", - "integrity": "sha512-L7Hym0yb20QIjvqeULUPOeh/cyvScdOAyJ6oRlh5dF0+w92hf3OiTk1q15KBijde7jGEe+0R4aOmtW8gkPNIzg==", - "requires": { - "h2x-traverse": "^1.1.0" - } - }, - "h2x-parse": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/h2x-parse/-/h2x-parse-1.1.1.tgz", - "integrity": "sha512-WRSmPF+tIWuUXVEZaYRhcZx/JGEJx8LjZpDDtrvMr5m/GTR0NerydCik5dRzcKXPWCtfXxuJRLR4v2P4HB2B1A==", - "requires": { - "h2x-types": "^1.1.0", - "jsdom": ">=11.0.0" - } - }, - "h2x-plugin-jsx": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/h2x-plugin-jsx/-/h2x-plugin-jsx-1.2.0.tgz", - "integrity": "sha512-a7Vb3BHhJJq0dPDNdqguEyQirENkVsFtvM2YkiaT5h/fmGhmM1nDy3BLeJeSKi2tL2g9v4ykm2Z+GG9QrhDgPA==", - "requires": { - "h2x-types": "^1.1.0" - } - }, - "h2x-traverse": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/h2x-traverse/-/h2x-traverse-1.1.0.tgz", - "integrity": "sha512-1ND8ZbISLSUgpLHYJRvhvElITvs0g44L7RxjeXViz5XP6rooa+FtXTFLByl2Yg01zj2txubifHIuU4pgvj8l+A==", - "requires": { - "h2x-types": "^1.1.0" - } - }, - "h2x-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/h2x-types/-/h2x-types-1.1.0.tgz", - "integrity": "sha512-QdH5qfLcdF209UsCdM0ZNZ9Dwm2PHvMfeLZtivBrjX3Y/df4US2pwsUC4HBfWhye/mx/t6puODeC7Oacb/Ol8g==" - }, - "handle-thing": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", - "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=" - }, - "handlebars": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.0", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "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.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, - "harmony-reflect": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", - "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "hex-color-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", - "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" - }, - "history": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", - "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", - "requires": { - "@babel/runtime": "^7.7.6" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hoopy": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", - "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==" - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "hsl-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz", - "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=" - }, - "hsla-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz", - "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=" - }, - "html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "requires": { - "whatwg-encoding": "^2.0.0" - } - }, - "html-entities": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz", - "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==" - }, - "html-minifier": { - "version": "3.5.21", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", - "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", - "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" - }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" - } - } - }, - "html-webpack-plugin": { - "version": "4.0.0-alpha.2", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-alpha.2.tgz", - "integrity": "sha512-tyvhjVpuGqD7QYHi1l1drMQTg5i+qRxpQEGbdnYFREgOKy7aFDf/ocQ/V1fuEDlQx7jV2zMap3Hj2nE9i5eGXw==", - "requires": { - "@types/tapable": "1.0.2", - "html-minifier": "^3.2.3", - "loader-utils": "^1.1.0", - "lodash": "^4.17.10", - "pretty-error": "^2.0.2", - "tapable": "^1.0.0", - "util.promisify": "1.0.0" - }, - "dependencies": { - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - } - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" - }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } - }, - "http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==" - }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - } - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "http-proxy-middleware": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", - "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", - "requires": { - "http-proxy": "^1.16.2", - "is-glob": "^4.0.0", - "lodash": "^4.17.5", - "micromatch": "^3.1.9" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "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-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "requires": { - "agent-base": "6", - "debug": "4" - }, - "dependencies": { - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "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" - } - }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" - }, - "icss-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", - "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", - "requires": { - "postcss": "^6.0.1" - } - }, - "identity-obj-proxy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", - "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=", - "requires": { - "harmony-reflect": "^1.4.6" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" - }, - "immer": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/immer/-/immer-1.7.2.tgz", - "integrity": "sha512-4Urocwu9+XLDJw4Tc6ZCg7APVjjLInCFvO4TwGsAYV5zT6YYSor14dsZR0+0tHlDIN92cFUOq+i7fC00G5vTxA==" - }, - "import-cwd": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", - "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", - "requires": { - "import-from": "^2.1.0" - } - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-from": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", - "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", - "requires": { - "resolve-from": "^3.0.0" - } - }, - "import-local": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", - "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", - "requires": { - "pkg-dir": "^2.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" - }, - "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.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "internal-ip": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz", - "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==", - "requires": { - "default-gateway": "^2.6.0", - "ipaddr.js": "^1.5.2" - } - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "requires": { - "loose-envify": "^1.0.0" - } - }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "requires": { - "kind-of": "^6.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "optional": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "requires": { - "ci-info": "^1.5.0" - } - }, - "is-color-stop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz", - "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=", - "requires": { - "css-color-names": "^0.0.4", - "hex-color-regex": "^1.1.0", - "hsl-regex": "^1.0.0", - "hsla-regex": "^1.0.0", - "rgb-regex": "^1.0.1", - "rgba-regex": "^1.0.0" - } - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "requires": { - "kind-of": "^6.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "requires": { - "is-primitive": "^2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-finite": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", - "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-generator-fn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz", - "integrity": "sha1-lp1J4bszKfa7fwkIm+JleLLd1Go=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "^3.0.1" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" - }, - "is-root": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.0.0.tgz", - "integrity": "sha512-F/pJIk8QD6OX5DNhRB7hWamLsUilmkDGho48KbgZ6xg/lmAZXHxzXQ91jzB3yRSw5kdQGGGc4yz8HYhTYIMWPg==" - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "requires": { - "punycode": "2.x.x" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "istanbul-api": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", - "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", - "requires": { - "async": "^2.1.4", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.2.1", - "istanbul-lib-hook": "^1.2.2", - "istanbul-lib-instrument": "^1.10.2", - "istanbul-lib-report": "^1.1.5", - "istanbul-lib-source-maps": "^1.2.6", - "istanbul-reports": "^1.5.1", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" - } - }, - "istanbul-lib-coverage": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", - "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==" - }, - "istanbul-lib-hook": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", - "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", - "requires": { - "append-transform": "^0.4.0" - } - }, - "istanbul-lib-instrument": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", - "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", - "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.1", - "semver": "^5.3.0" - } - }, - "istanbul-lib-report": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", - "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", - "requires": { - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", - "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.1", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - } - }, - "istanbul-reports": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", - "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", - "requires": { - "handlebars": "^4.0.3" - } - }, - "jest": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-23.6.0.tgz", - "integrity": "sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw==", - "requires": { - "import-local": "^1.0.0", - "jest-cli": "^23.6.0" - } - }, - "jest-changed-files": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-23.4.2.tgz", - "integrity": "sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA==", - "requires": { - "throat": "^4.0.0" - } - }, - "jest-cli": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.6.0.tgz", - "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==", - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "import-local": "^1.0.0", - "is-ci": "^1.0.10", - "istanbul-api": "^1.3.1", - "istanbul-lib-coverage": "^1.2.0", - "istanbul-lib-instrument": "^1.10.1", - "istanbul-lib-source-maps": "^1.2.4", - "jest-changed-files": "^23.4.2", - "jest-config": "^23.6.0", - "jest-environment-jsdom": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve-dependencies": "^23.6.0", - "jest-runner": "^23.6.0", - "jest-runtime": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "jest-watcher": "^23.4.0", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "node-notifier": "^5.2.1", - "prompts": "^0.1.9", - "realpath-native": "^1.0.0", - "rimraf": "^2.5.4", - "slash": "^1.0.0", - "string-length": "^2.0.0", - "strip-ansi": "^4.0.0", - "which": "^1.2.12", - "yargs": "^11.0.0" - }, - "dependencies": { - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - } - } - }, - "jest-config": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.6.0.tgz", - "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==", - "requires": { - "babel-core": "^6.0.0", - "babel-jest": "^23.6.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^23.4.0", - "jest-environment-node": "^23.4.0", - "jest-get-type": "^22.1.0", - "jest-jasmine2": "^23.6.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "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" - } - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "jest-docblock": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-23.2.0.tgz", - "integrity": "sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c=", - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz", - "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==", - "requires": { - "chalk": "^2.0.1", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "jest-environment-jsdom": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz", - "integrity": "sha1-BWp5UrP+pROsYqFAosNox52eYCM=", - "requires": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0", - "jsdom": "^11.5.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" - } - } - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==" - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "requires": { - "cssom": "0.3.x" - } - }, - "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" - }, - "dependencies": { - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "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" - } - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "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" - } - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - } - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" - }, - "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 - }, - "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" - } - }, - "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" - } - }, - "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": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "ws": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", - "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", - "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==" - } - } - }, - "jest-environment-node": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-23.4.0.tgz", - "integrity": "sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA=", - "requires": { - "jest-mock": "^23.2.0", - "jest-util": "^23.4.0" - } - }, - "jest-haste-map": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.6.0.tgz", - "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==", - "requires": { - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.1.11", - "invariant": "^2.2.4", - "jest-docblock": "^23.2.0", - "jest-serializer": "^23.0.1", - "jest-worker": "^23.2.0", - "micromatch": "^2.3.11", - "sane": "^2.0.0" - } - }, - "jest-jasmine2": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz", - "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==", - "requires": { - "babel-traverse": "^6.0.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^23.6.0", - "is-generator-fn": "^1.0.0", - "jest-diff": "^23.6.0", - "jest-each": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "jest-diff": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", - "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", - "requires": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - } - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "jest-leak-detector": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz", - "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==", - "requires": { - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "jest-matcher-utils": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz", - "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==", - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "jest-message-util": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-23.4.0.tgz", - "integrity": "sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8=", - "requires": { - "@babel/code-frame": "^7.0.0-beta.35", - "chalk": "^2.0.1", - "micromatch": "^2.3.11", - "slash": "^1.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-23.2.0.tgz", - "integrity": "sha1-rRxg8p6HGdR8JuETgJi20YsmETQ=" - }, - "jest-pnp-resolver": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.0.1.tgz", - "integrity": "sha512-kzhvJQp+9k0a/hpvIIzOJgOwfOqmnohdrAMZW2EscH3kxR2VWD7EcPa10cio8EK9V7PcD75bhG1pFnO70zGwSQ==" - }, - "jest-regex-util": { - "version": "23.3.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-23.3.0.tgz", - "integrity": "sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U=" - }, - "jest-resolve": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz", - "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==", - "requires": { - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "realpath-native": "^1.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz", - "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==", - "requires": { - "jest-regex-util": "^23.3.0", - "jest-snapshot": "^23.6.0" - } - }, - "jest-runner": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.6.0.tgz", - "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==", - "requires": { - "exit": "^0.1.2", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-docblock": "^23.2.0", - "jest-haste-map": "^23.6.0", - "jest-jasmine2": "^23.6.0", - "jest-leak-detector": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-runtime": "^23.6.0", - "jest-util": "^23.4.0", - "jest-worker": "^23.2.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } - }, - "jest-runtime": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.6.0.tgz", - "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==", - "requires": { - "babel-core": "^6.0.0", - "babel-plugin-istanbul": "^4.1.6", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "exit": "^0.1.2", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.11", - "jest-config": "^23.6.0", - "jest-haste-map": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.6.0", - "jest-snapshot": "^23.6.0", - "jest-util": "^23.4.0", - "jest-validate": "^23.6.0", - "micromatch": "^2.3.11", - "realpath-native": "^1.0.0", - "slash": "^1.0.0", - "strip-bom": "3.0.0", - "write-file-atomic": "^2.1.0", - "yargs": "^11.0.0" - }, - "dependencies": { - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } - }, - "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=" - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - } - } - }, - "jest-serializer": { - "version": "23.0.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-23.0.1.tgz", - "integrity": "sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU=" - }, - "jest-snapshot": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.6.0.tgz", - "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==", - "requires": { - "babel-types": "^6.0.0", - "chalk": "^2.0.1", - "jest-diff": "^23.6.0", - "jest-matcher-utils": "^23.6.0", - "jest-message-util": "^23.4.0", - "jest-resolve": "^23.6.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^23.6.0", - "semver": "^5.5.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "jest-diff": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", - "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", - "requires": { - "chalk": "^2.0.1", - "diff": "^3.2.0", - "jest-get-type": "^22.1.0", - "pretty-format": "^23.6.0" - } - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "jest-util": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-23.4.0.tgz", - "integrity": "sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE=", - "requires": { - "callsites": "^2.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.11", - "is-ci": "^1.0.10", - "jest-message-util": "^23.4.0", - "mkdirp": "^0.5.1", - "slash": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "jest-validate": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", - "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", - "requires": { - "chalk": "^2.0.1", - "jest-get-type": "^22.1.0", - "leven": "^2.1.0", - "pretty-format": "^23.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "jest-get-type": { - "version": "22.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.4.3.tgz", - "integrity": "sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w==" - }, - "pretty-format": { - "version": "23.6.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", - "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", - "requires": { - "ansi-regex": "^3.0.0", - "ansi-styles": "^3.2.0" - } - } - } - }, - "jest-watcher": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-23.4.0.tgz", - "integrity": "sha1-0uKM50+NrWxq/JIrksq+9u0FyRw=", - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "string-length": "^2.0.0" - } - }, - "jest-worker": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-23.2.0.tgz", - "integrity": "sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk=", - "requires": { - "merge-stream": "^1.0.1" - } - }, - "joi": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", - "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", - "requires": { - "hoek": "4.x.x", - "isemail": "3.x.x", - "topo": "2.x.x" - } - }, - "js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "jsdom": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", - "integrity": "sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==", - "requires": { - "abab": "^2.0.5", - "acorn": "^8.5.0", - "acorn-globals": "^6.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.1", - "decimal.js": "^10.3.1", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^3.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^10.0.0", - "ws": "^8.2.3", - "xml-name-validator": "^4.0.0" - }, - "dependencies": { - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" - } - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, - "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-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "~0.0.0" - } - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "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=" - }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "jsx-ast-utils": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz", - "integrity": "sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w==", - "requires": { - "array-includes": "^3.1.1", - "object.assign": "^4.1.0" - } - }, - "killable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", - "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==" - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "kleur": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", - "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==" - }, - "last-call-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz", - "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==", - "requires": { - "lodash": "^4.17.5", - "webpack-sources": "^1.1.0" - } - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "requires": { - "invert-kv": "^2.0.0" - } - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" - }, - "leven": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", - "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" - }, - "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" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "^1.2.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - } - } - }, - "loader-fs-cache": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz", - "integrity": "sha512-ldcgZpjNJj71n+2Mf6yetz+c9bM4xpKtNds4LbqXzU/PTdeAX0g3ytnU1AJMEcTk2Lex4Smpe3Q/eCTsvUBxbA==", - "requires": { - "find-cache-dir": "^0.1.1", - "mkdirp": "^0.5.1" - }, - "dependencies": { - "find-cache-dir": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", - "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", - "requires": { - "commondir": "^1.0.1", - "mkdirp": "^0.5.1", - "pkg-dir": "^1.0.0" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "requires": { - "find-up": "^1.0.0" - } - } - } - }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" - }, - "lodash.tail": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", - "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=" - }, - "lodash.template": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.templatesettings": "^4.0.0" - } - }, - "lodash.templatesettings": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", - "requires": { - "lodash._reinterpolate": "^3.0.0" - } - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "loglevel": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", - "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==" - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" - } - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "requires": { - "tmpl": "1.0.5" - } - }, - "mamacro": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==" - }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "requires": { - "p-defer": "^1.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "requires": { - "object-visit": "^1.0.0" - } - }, - "math-random": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", - "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==" - }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - } - } - }, - "memoize-one": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" - }, - "memoize-weak": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/memoize-weak/-/memoize-weak-1.0.2.tgz", - "integrity": "sha1-0AFaTHxs/yJj27tJ2x3CBuu5SRY=" - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - } - }, - "merge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", - "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==" - }, - "merge-deep": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", - "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", - "requires": { - "arr-union": "^3.1.0", - "clone-deep": "^0.2.4", - "kind-of": "^3.0.2" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "requires": { - "readable-stream": "^2.0.1" - } - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "miller-rabin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", - "requires": { - "bn.js": "^4.0.0", - "brorand": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==" - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "requires": { - "mime-db": "1.51.0" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" - }, - "mini-css-extract-plugin": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.3.tgz", - "integrity": "sha512-Mxs0nxzF1kxPv4TRi2NimewgXlJqh0rGE30vviCU2WHrpbta6wklnUV9dr9FUtoAHmB3p3LeXEC+ZjgHvB0Dzg==", - "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0", - "webpack-sources": "^1.1.0" - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.1.tgz", - "integrity": "sha512-reLxBcKUPNBnc/sVtAbxgRVFSegoGeLaSjmphNhcwcolhYLRgtJscn5mRl6YRZNQv40Y7P6JM2YhSIsbL9OB5A==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", - "requires": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=" - } - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, - "nan": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", - "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" - }, - "no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", - "requires": { - "lower-case": "^1.1.1" - } - }, - "node-forge": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", - "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" - }, - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=" - }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", - "requires": { - "inherits": "2.0.3" - } - } - } - }, - "node-notifier": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.5.tgz", - "integrity": "sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ==", - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" - }, - "normalize-url": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==" - }, - "normalize-wheel": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz", - "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU=" - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "requires": { - "boolbase": "^1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "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==" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - } - } - }, - "object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" - }, - "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "requires": { - "isobject": "^3.0.0" - } - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "requires": { - "isobject": "^3.0.1" - } - }, - "object.values": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", - "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "opn": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", - "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", - "requires": { - "is-wsl": "^1.1.0" - } - }, - "optimize-css-assets-webpack-plugin": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.1.tgz", - "integrity": "sha512-Rqm6sSjWtx9FchdP0uzTQDc7GXDKnwVEGoSxjezPkzMewx7gEWE9IMUYKmigTRC4U3RaNSwYVnUDLuIdtTpm0A==", - "requires": { - "cssnano": "^4.1.0", - "last-call-webpack-plugin": "^3.0.0" - } - }, - "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" - } - }, - "original": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", - "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", - "requires": { - "url-parse": "^1.4.3" - } - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "dependencies": { - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==" - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - } - }, - "param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "requires": { - "no-case": "^2.2.0" - } - }, - "parse-asn1": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", - "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", - "requires": { - "asn1.js": "^5.2.0", - "browserify-aes": "^1.0.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" - }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - }, - "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=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "requires": { - "pify": "^3.0.0" - } - }, - "pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "optional": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "requires": { - "find-up": "^2.1.0" - } - }, - "pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", - "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", - "requires": { - "find-up": "^2.1.0" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" - }, - "pnp-webpack-plugin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.1.0.tgz", - "integrity": "sha512-CPCdcFxx7fEcDMWTDjXe2Wypt4JuMt4q5Q2UrpTcyBBkLiCIyPEh/mCGmUWIcNkKGyXwQ9Y2wVhlKm6ketiBNQ==" - }, - "portfinder": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", - "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", - "requires": { - "async": "^2.6.2", - "debug": "^3.1.1", - "mkdirp": "^0.5.5" - } - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" - }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-attribute-case-insensitive": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz", - "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^6.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-calc": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz", - "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==", - "requires": { - "postcss": "^7.0.27", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-color-functional-notation": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz", - "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-color-hex-alpha": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz", - "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==", - "requires": { - "postcss": "^7.0.14", - "postcss-values-parser": "^2.0.1" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-color-mod-function": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz", - "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==", - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-color-rebeccapurple": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz", - "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-colormin": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz", - "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==", - "requires": { - "browserslist": "^4.0.0", - "color": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-convert-values": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz", - "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-custom-media": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz", - "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==", - "requires": { - "postcss": "^7.0.14" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-custom-properties": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz", - "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==", - "requires": { - "postcss": "^7.0.17", - "postcss-values-parser": "^2.0.1" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-custom-selectors": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz", - "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-dir-pseudo-class": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz", - "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-discard-comments": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz", - "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-discard-duplicates": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz", - "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-discard-empty": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz", - "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-discard-overridden": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz", - "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-env-function": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz", - "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-flexbugs-fixes": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.1.0.tgz", - "integrity": "sha512-jr1LHxQvStNNAHlgco6PzY308zvLklh7SJVYuWUwyUQncofaAlD2l+P/gxKHOdqWKe7xJSkVLFF/2Tp+JqMSZA==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-focus-visible": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz", - "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-focus-within": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz", - "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-font-variant": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz", - "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-gap-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz", - "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-image-set-function": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz", - "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-initial": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz", - "integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-lab-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz", - "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==", - "requires": { - "@csstools/convert-colors": "^1.4.0", - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-load-config": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz", - "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==", - "requires": { - "cosmiconfig": "^5.0.0", - "import-cwd": "^2.0.0" - } - }, - "postcss-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz", - "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==", - "requires": { - "loader-utils": "^1.1.0", - "postcss": "^7.0.0", - "postcss-load-config": "^2.0.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-logical": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz", - "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-media-minmax": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz", - "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-merge-longhand": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz", - "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==", - "requires": { - "css-color-names": "0.0.4", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "stylehacks": "^4.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-merge-rules": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz", - "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "cssnano-util-same-parent": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0", - "vendors": "^1.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-minify-font-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz", - "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-minify-gradients": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz", - "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "is-color-stop": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-minify-params": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz", - "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==", - "requires": { - "alphanum-sort": "^1.0.0", - "browserslist": "^4.0.0", - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-minify-selectors": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz", - "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==", - "requires": { - "alphanum-sort": "^1.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-modules-extract-imports": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", - "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", - "requires": { - "postcss": "^6.0.1" - } - }, - "postcss-modules-local-by-default": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", - "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", - "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - } - }, - "postcss-modules-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", - "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", - "requires": { - "css-selector-tokenizer": "^0.7.0", - "postcss": "^6.0.1" - } - }, - "postcss-modules-values": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", - "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", - "requires": { - "icss-replace-symbols": "^1.1.0", - "postcss": "^6.0.1" - } - }, - "postcss-nesting": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz", - "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-charset": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz", - "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-display-values": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz", - "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-positions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz", - "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-repeat-style": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz", - "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-string": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz", - "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==", - "requires": { - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-timing-functions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz", - "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-unicode": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz", - "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==", - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-url": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz", - "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==", - "requires": { - "is-absolute-url": "^2.0.0", - "normalize-url": "^3.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-normalize-whitespace": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz", - "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-ordered-values": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz", - "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==", - "requires": { - "cssnano-util-get-arguments": "^4.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-overflow-shorthand": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz", - "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-page-break": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz", - "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-place": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz", - "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==", - "requires": { - "postcss": "^7.0.2", - "postcss-values-parser": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-preset-env": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.0.6.tgz", - "integrity": "sha512-W1Wtqngl7BMe4s9o76odTaVs4HXVLhOHD+L5Ez+7x15yiA+98W/WVO6IPlC1q9BIkgAckRtUFmEDr0sNufXZIQ==", - "requires": { - "autoprefixer": "^9.1.5", - "browserslist": "^4.1.1", - "caniuse-lite": "^1.0.30000887", - "cssdb": "^3.2.1", - "postcss": "^7.0.2", - "postcss-attribute-case-insensitive": "^4.0.0", - "postcss-color-functional-notation": "^2.0.1", - "postcss-color-hex-alpha": "^5.0.2", - "postcss-color-mod-function": "^3.0.3", - "postcss-color-rebeccapurple": "^4.0.1", - "postcss-custom-media": "^7.0.4", - "postcss-custom-properties": "^8.0.5", - "postcss-custom-selectors": "^5.1.2", - "postcss-dir-pseudo-class": "^5.0.0", - "postcss-env-function": "^2.0.2", - "postcss-focus-visible": "^4.0.0", - "postcss-focus-within": "^3.0.0", - "postcss-font-variant": "^4.0.0", - "postcss-gap-properties": "^2.0.0", - "postcss-image-set-function": "^3.0.1", - "postcss-initial": "^3.0.0", - "postcss-lab-function": "^2.0.1", - "postcss-logical": "^3.0.0", - "postcss-media-minmax": "^4.0.0", - "postcss-nesting": "^7.0.0", - "postcss-overflow-shorthand": "^2.0.0", - "postcss-page-break": "^2.0.0", - "postcss-place": "^4.0.1", - "postcss-pseudo-class-any-link": "^6.0.0", - "postcss-replace-overflow-wrap": "^3.0.0", - "postcss-selector-matches": "^4.0.0", - "postcss-selector-not": "^4.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-pseudo-class-any-link": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz", - "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==", - "requires": { - "postcss": "^7.0.2", - "postcss-selector-parser": "^5.0.0-rc.3" - }, - "dependencies": { - "cssesc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", - "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" - }, - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-selector-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", - "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", - "requires": { - "cssesc": "^2.0.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-reduce-initial": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz", - "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==", - "requires": { - "browserslist": "^4.0.0", - "caniuse-api": "^3.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-reduce-transforms": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz", - "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==", - "requires": { - "cssnano-util-get-match": "^4.0.0", - "has": "^1.0.0", - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-replace-overflow-wrap": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz", - "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==", - "requires": { - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-safe-parser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-4.0.1.tgz", - "integrity": "sha512-xZsFA3uX8MO3yAda03QrG3/Eg1LN3EPfjjf07vke/46HERLZyHrTsQ9E1r1w1W//fWEhtYNndo2hQplN2cVpCQ==", - "requires": { - "postcss": "^7.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-selector-matches": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz", - "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==", - "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-selector-not": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz", - "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==", - "requires": { - "balanced-match": "^1.0.0", - "postcss": "^7.0.2" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz", - "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==", - "requires": { - "postcss": "^7.0.0", - "postcss-value-parser": "^3.0.0", - "svgo": "^1.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-unique-selectors": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz", - "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==", - "requires": { - "alphanum-sort": "^1.0.0", - "postcss": "^7.0.0", - "uniqs": "^2.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "postcss-value-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", - "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==" - }, - "postcss-values-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz", - "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==", - "requires": { - "flatten": "^1.0.2", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" - }, - "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==" - }, - "pretty-bytes": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", - "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=" - }, - "pretty-error": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", - "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", - "requires": { - "lodash": "^4.17.20", - "renderkid": "^2.0.4" - } - }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "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==" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" - }, - "promise": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/promise/-/promise-8.0.2.tgz", - "integrity": "sha512-EIyzM39FpVOMbqgzEHhxdrEhtOSDOtjMZQ0M6iVfCE+kWNgCkAyOdnuCWqfmflylftfadU6FkiMgHZA2kUzwRw==", - "requires": { - "asap": "~2.0.6" - } - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" - }, - "prompts": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-0.1.14.tgz", - "integrity": "sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w==", - "requires": { - "kleur": "^2.0.1", - "sisteransi": "^0.1.1" - } - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - }, - "dependencies": { - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - } - } - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" - }, - "qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==" - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, - "raf": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.0.tgz", - "integrity": "sha512-pDP/NMRAXoTfrhCfyfSEwJAKLaxBU9eApMeBPB1TkDouZmvPerIClV8lTAd+uF8ZiTaVl69e1FCxQrAd/VTjGw==", - "requires": { - "performance-now": "^2.1.0" - } - }, - "randomatic": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", - "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", - "requires": { - "is-number": "^4.0.0", - "kind-of": "^6.0.0", - "math-random": "^1.0.1" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", - "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", - "requires": { - "bytes": "3.1.1", - "http-errors": "1.8.1", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==" - } - } - }, - "react": { - "version": "16.8.0", - "resolved": "https://registry.npmjs.org/react/-/react-16.8.0.tgz", - "integrity": "sha512-g+nikW2D48kqgWSPwNo0NH9tIGG3DsQFlrtrQ1kj6W77z5ahyIHG0w8kPpz4Sdj6gyLnz0lEd/xsjOoGge2MYQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.0" - } - }, - "react-app-polyfill": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-0.1.3.tgz", - "integrity": "sha512-Fl5Pic4F15G05qX7RmUqPZr1MtyFKJKSlRwMhel4kvDLrk/KcQ9QbpvyMTzv/0NN5957XFQ7r1BNHWi7qN59Pw==", - "requires": { - "core-js": "2.5.7", - "object-assign": "4.1.1", - "promise": "8.0.2", - "raf": "3.4.0", - "whatwg-fetch": "3.0.0" - }, - "dependencies": { - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" - } - } - }, - "react-burger-menu": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/react-burger-menu/-/react-burger-menu-3.0.6.tgz", - "integrity": "sha512-Xikyl8VRkQBOyFVoMKpbScTLG6LlW64rajiquyCGwtpPswrDxaifusKckzTWAOH0At40Boguhj5lXq451NO0LA==", - "requires": { - "browserify-optional": "^1.0.0", - "classnames": "^2.2.6", - "eve": "~0.5.1", - "prop-types": "^15.7.2", - "snapsvg-cjs": "0.0.6" - } - }, - "react-dev-utils": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-6.1.1.tgz", - "integrity": "sha512-ThbJ86coVd6wV/QiTo8klDTvdAJ1WsFCGQN07+UkN+QN9CtCSsl/+YuDJToKGeG8X4j9HMGXNKbk2QhPAZr43w==", - "requires": { - "@babel/code-frame": "7.0.0", - "address": "1.0.3", - "browserslist": "4.1.1", - "chalk": "2.4.1", - "cross-spawn": "6.0.5", - "detect-port-alt": "1.1.6", - "escape-string-regexp": "1.0.5", - "filesize": "3.6.1", - "find-up": "3.0.0", - "global-modules": "1.0.0", - "globby": "8.0.1", - "gzip-size": "5.0.0", - "immer": "1.7.2", - "inquirer": "6.2.0", - "is-root": "2.0.0", - "loader-utils": "1.1.0", - "opn": "5.4.0", - "pkg-up": "2.0.0", - "react-error-overlay": "^5.1.0", - "recursive-readdir": "2.2.2", - "shell-quote": "1.6.1", - "sockjs-client": "1.1.5", - "strip-ansi": "4.0.0", - "text-table": "0.2.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" - }, - "browserslist": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.1.1.tgz", - "integrity": "sha512-VBorw+tgpOtZ1BYhrVSVTzTt/3+vSE3eFUh0N2GCFK1HffceOaf32YS/bs6WiFhjDAblAFrx85jMy3BG9fBK2Q==", - "requires": { - "caniuse-lite": "^1.0.30000884", - "electron-to-chromium": "^1.3.62", - "node-releases": "^1.0.0-alpha.11" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "inquirer": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", - "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.0", - "figures": "^2.0.0", - "lodash": "^4.17.10", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.1.0", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - } - }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "node-releases": { - "version": "1.1.77", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", - "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==" - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - } - } - }, - "react-dom": { - "version": "16.8.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.0.tgz", - "integrity": "sha512-dBzoAGYZpW9Yggp+CzBPC7q1HmWSeRc93DWrwbskmG1eHJWznZB/p0l/Sm+69leIGUS91AXPB/qB3WcPnKx8Sw==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.0" - } - }, - "react-error-overlay": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-5.1.6.tgz", - "integrity": "sha512-X1Y+0jR47ImDVr54Ab6V9eGk0Hnu7fVWGeHQSOXHf/C2pF9c6uy3gef8QUeuUiWlNb0i08InPSE5a/KJzNzw1Q==" - }, - "react-router": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.2.tgz", - "integrity": "sha512-/MbxyLzd7Q7amp4gDOGaYvXwhEojkJD5BtExkuKmj39VEE0m3l/zipf6h2WIB2jyAO0lI6NGETh4RDcktRm4AQ==", - "requires": { - "history": "^5.2.0" - } - }, - "react-router-dom": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.2.tgz", - "integrity": "sha512-AtYEsAST7bDD4dLSQHDnk/qxWLJdad5t1HFa1qJyUrCeGgEuCSw0VB/27ARbF9Fi/W5598ujvJOm3ujUCVzuYQ==", - "requires": { - "history": "^5.2.0", - "react-router": "6.2.2" - } - }, - "react-scripts": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-2.0.3.tgz", - "integrity": "sha512-Hw6P9vJ9vXWdo5J752lzN6NpmY3DpEjp5VD+V+N+61TY5+UY/oKtfF+23ZRFBCkULlVvQdo25Sw92HKA2wI8sw==", - "requires": { - "@babel/core": "7.1.0", - "@svgr/webpack": "2.4.1", - "babel-core": "7.0.0-bridge.0", - "babel-eslint": "9.0.0", - "babel-jest": "23.6.0", - "babel-loader": "8.0.4", - "babel-plugin-named-asset-import": "^0.2.2", - "babel-preset-react-app": "^5.0.2", - "bfj": "6.1.1", - "case-sensitive-paths-webpack-plugin": "2.1.2", - "chalk": "2.4.1", - "css-loader": "1.0.0", - "dotenv": "6.0.0", - "dotenv-expand": "4.2.0", - "eslint": "5.6.0", - "eslint-config-react-app": "^3.0.3", - "eslint-loader": "2.1.1", - "eslint-plugin-flowtype": "2.50.1", - "eslint-plugin-import": "2.14.0", - "eslint-plugin-jsx-a11y": "6.1.1", - "eslint-plugin-react": "7.11.1", - "file-loader": "2.0.0", - "fs-extra": "7.0.0", - "fsevents": "1.2.4", - "html-webpack-plugin": "4.0.0-alpha.2", - "identity-obj-proxy": "3.0.0", - "jest": "23.6.0", - "jest-pnp-resolver": "1.0.1", - "jest-resolve": "23.6.0", - "mini-css-extract-plugin": "0.4.3", - "optimize-css-assets-webpack-plugin": "5.0.1", - "pnp-webpack-plugin": "1.1.0", - "postcss-flexbugs-fixes": "4.1.0", - "postcss-loader": "3.0.0", - "postcss-preset-env": "6.0.6", - "postcss-safe-parser": "4.0.1", - "react-app-polyfill": "^0.1.3", - "react-dev-utils": "^6.0.3", - "resolve": "1.8.1", - "sass-loader": "7.1.0", - "style-loader": "0.23.0", - "terser-webpack-plugin": "1.1.0", - "url-loader": "1.1.1", - "webpack": "4.19.1", - "webpack-dev-server": "3.1.9", - "webpack-manifest-plugin": "2.0.4", - "workbox-webpack-plugin": "3.6.2" - }, - "dependencies": { - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - }, - "dependencies": { - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "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" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "requires": { - "util.promisify": "^1.0.0" - } - }, - "recursive-readdir": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", - "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", - "requires": { - "minimatch": "3.0.4" - }, - "dependencies": { - "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" - } - } - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" - }, - "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" - }, - "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==" - }, - "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==" - }, - "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - } - } - }, - "regl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/regl/-/regl-1.7.0.tgz", - "integrity": "sha512-bEAtp/qrtKucxXSJkD4ebopFZYP0q1+3Vb2WECWv/T8yQEgKxDxJ7ztO285tAMaYZVR6mM1GgI6CCn8FROtL1w==" - }, - "regl-worldview": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/regl-worldview/-/regl-worldview-0.18.0.tgz", - "integrity": "sha512-/ZEmF/CKloZ0+0/AYrXYdQdLEHrjjLPp+vzhBmgVP/UIOrv+nt0BeRNM+xenRKknBuYE1M080q54M+aoJS9tDg==", - "requires": { - "@babel/runtime": "^7.3.1", - "@mapbox/tiny-sdf": "2.0.4", - "distance-to-line-segment": "0.2.0", - "draco3d": "^1.4.1", - "earcut": "^2.1.3", - "gl-matrix": ">=2.6.1", - "lodash": "^4.17.11", - "memoize-one": "^5.1.1", - "memoize-weak": "^1.0.2", - "normalize-wheel": "1.0.1", - "regl": "^1.3.1", - "reselect": "^3.0.1", - "shallowequal": "1.1.0" - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "renderkid": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", - "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", - "requires": { - "css-select": "^4.1.3", - "dom-converter": "^0.2.0", - "htmlparser2": "^6.1.0", - "lodash": "^4.17.21", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "^1.0.0" - } - }, - "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": { - "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" - } - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - }, - "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.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "requires": { - "request-promise-core": "1.1.4", - "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" - } - } - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" - }, - "dependencies": { - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "requires": { - "callsites": "^0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" - } - } - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "reselect": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/reselect/-/reselect-3.0.1.tgz", - "integrity": "sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc=" - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "requires": { - "path-parse": "^1.0.5" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" - }, - "rgb-regex": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz", - "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=" - }, - "rgba-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz", - "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=" - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "requires": { - "glob": "^7.1.3" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rsvp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", - "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==" - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "requires": { - "aproba": "^1.1.1" - } - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "requires": { - "tslib": "^1.9.0" - } - }, - "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==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sane": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/sane/-/sane-2.5.2.tgz", - "integrity": "sha1-tNwYYcIbQn6SlQej51HiosuKs/o=", - "requires": { - "anymatch": "^2.0.0", - "capture-exit": "^1.2.0", - "exec-sh": "^0.2.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.3", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5", - "watch": "~0.18.0" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "sass-loader": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.1.0.tgz", - "integrity": "sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==", - "requires": { - "clone-deep": "^2.0.1", - "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", - "neo-async": "^2.5.0", - "pify": "^3.0.0", - "semver": "^5.5.0" - }, - "dependencies": { - "clone-deep": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", - "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", - "requires": { - "for-own": "^1.0.0", - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.0", - "shallow-clone": "^1.0.0" - } - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "requires": { - "for-in": "^1.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "shallow-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", - "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", - "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^5.0.0", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "requires": { - "xmlchars": "^2.2.0" - } - }, - "scheduler": { - "version": "0.13.6", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", - "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" - }, - "selfsigned": { - "version": "1.10.14", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.14.tgz", - "integrity": "sha512-lkjaiAye+wBZDCBsu5BGi0XiLRxeUlsGod5ZP924CRSEoGuZAw/f7y9RKu28rwTfiHVhdavhB0qH0INV6P1lEA==", - "requires": { - "node-forge": "^0.10.0" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "1.8.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "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" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - } - } - }, - "serialize-javascript": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", - "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==" - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "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" - } - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - } - } - }, - "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.2" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shallow-clone": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", - "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", - "requires": { - "is-buffer": "^1.0.2" - } - }, - "lazy-cache": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=" - } - } - }, - "shallowequal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "requires": { - "is-arrayish": "^0.3.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - } - } - }, - "sisteransi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-0.1.1.tgz", - "integrity": "sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g==" - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "requires": { - "is-fullwidth-code-point": "^2.0.0" - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "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" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "requires": { - "kind-of": "^3.2.0" - } - }, - "snapsvg": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/snapsvg/-/snapsvg-0.5.1.tgz", - "integrity": "sha1-DK9Sx5GJopB0b8RGzF6GP2vd3+M=", - "requires": { - "eve": "~0.5.1" - } - }, - "snapsvg-cjs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/snapsvg-cjs/-/snapsvg-cjs-0.0.6.tgz", - "integrity": "sha1-Oy9WryVz09Nkw+1b+IhXRfTS3eE=", - "requires": { - "snapsvg": "0.5.1" - } - }, - "sockjs": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", - "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", - "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.0.1" - }, - "dependencies": { - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "requires": { - "websocket-driver": ">=0.5.1" - } - } - } - }, - "sockjs-client": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.5.tgz", - "integrity": "sha1-G7fA9yIsQPQq3xT0RCy9Eml3GoM=", - "requires": { - "debug": "^2.6.6", - "eventsource": "0.1.6", - "faye-websocket": "~0.11.0", - "inherits": "^2.0.1", - "json3": "^3.3.2", - "url-parse": "^1.1.8" - }, - "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=" - } - } - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==" - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==" - }, - "spdy": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", - "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", - "requires": { - "debug": "^2.6.8", - "handle-thing": "^1.2.5", - "http-deceiver": "^1.2.7", - "safe-buffer": "^5.0.1", - "select-hose": "^2.0.0", - "spdy-transport": "^2.0.18" - }, - "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=" - } - } - }, - "spdy-transport": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.1.tgz", - "integrity": "sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==", - "requires": { - "debug": "^2.6.8", - "detect-node": "^2.0.3", - "hpack.js": "^2.1.6", - "obuf": "^1.1.1", - "readable-stream": "^2.2.9", - "safe-buffer": "^5.0.1", - "wbuf": "^1.7.2" - }, - "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=" - } - } - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "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" - } - }, - "ssri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", - "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "stable": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" - }, - "stack-utils": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.5.tgz", - "integrity": "sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ==", - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" - } - } - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - } - }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" - }, - "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" - } - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "stringify-object": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", - "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", - "requires": { - "get-own-enumerable-property-symbols": "^3.0.0", - "is-obj": "^1.0.1", - "is-regexp": "^1.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "^0.2.0" - } - }, - "strip-comments": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz", - "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==", - "requires": { - "babel-extract-comments": "^1.0.0", - "babel-plugin-transform-object-rest-spread": "^6.26.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "style-loader": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.0.tgz", - "integrity": "sha512-uCcN7XWHkqwGVt7skpInW6IGO1tG6ReyFQ1Cseh0VcN6VdcFQi62aG/2F3Y9ueA8x4IVlfaSUxpmQXQD9QrEuQ==", - "requires": { - "loader-utils": "^1.1.0", - "schema-utils": "^0.4.5" - }, - "dependencies": { - "schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "stylehacks": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", - "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==", - "requires": { - "browserslist": "^4.0.0", - "postcss": "^7.0.0", - "postcss-selector-parser": "^3.0.0" - }, - "dependencies": { - "picocolors": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", - "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" - }, - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "postcss-selector-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz", - "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==", - "requires": { - "dot-prop": "^5.2.0", - "indexes-of": "^1.0.1", - "uniq": "^1.0.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "svgo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", - "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", - "requires": { - "chalk": "^2.4.1", - "coa": "^2.0.2", - "css-select": "^2.0.0", - "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.37", - "csso": "^4.0.2", - "js-yaml": "^3.13.1", - "mkdirp": "~0.5.1", - "object.values": "^1.1.0", - "sax": "~1.2.4", - "stable": "^0.1.8", - "unquote": "~1.1.1", - "util.promisify": "~1.0.0" - }, - "dependencies": { - "css-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", - "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", - "requires": { - "boolbase": "^1.0.0", - "css-what": "^3.2.1", - "domutils": "^1.7.0", - "nth-check": "^1.0.2" - } - }, - "css-what": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", - "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==" - }, - "dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "domutils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", - "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", - "requires": { - "dom-serializer": "0", - "domelementtype": "1" - }, - "dependencies": { - "domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" - } - } - }, - "nth-check": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", - "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", - "requires": { - "boolbase": "~1.0.0" - } - }, - "util.promisify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", - "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.2", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.0" - } - } - } - }, - "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==" - }, - "table": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", - "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" - }, - "terser": { - "version": "3.17.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", - "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", - "requires": { - "commander": "^2.19.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.10" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "terser-webpack-plugin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.1.0.tgz", - "integrity": "sha512-61lV0DSxMAZ8AyZG7/A4a3UPlrbOBo8NIQ4tJzLPAdGOQ+yoNC7l5ijEow27lBAL2humer01KLS6bGIMYQxKoA==", - "requires": { - "cacache": "^11.0.2", - "find-cache-dir": "^2.0.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "terser": "^3.8.1", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "requires": { - "find-up": "^3.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "test-exclude": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.3.tgz", - "integrity": "sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==", - "requires": { - "arrify": "^1.0.1", - "micromatch": "^2.3.11", - "object-assign": "^4.1.0", - "read-pkg-up": "^1.0.1", - "require-main-filename": "^1.0.1" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=" - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" - }, - "timers-browserify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", - "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timsort": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", - "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - } - } - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "topo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", - "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", - "requires": { - "hoek": "4.x.x" - } - }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "requires": { - "punycode": "^2.1.1" - } - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" - }, - "tryer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", - "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" - }, - "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": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" - }, - "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" - } - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "uglify-js": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", - "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==", - "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", - "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "uglifyjs-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", - "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.5", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "cacache": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", - "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", - "y18n": "^4.0.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^2.0.1", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "ssri": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", - "requires": { - "safe-buffer": "^5.1.1" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==" - }, - "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==" - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "unquote": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", - "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" - }, - "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "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=" - } - } - }, - "url-loader": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz", - "integrity": "sha512-vugEeXjyYFBCUOpX+ZuaunbK3QXMKaQ3zUnRfIpRBlGkY7QizCnzyyn2ASfcxsvyU3ef+CJppVywnl3Kgf13Gg==", - "requires": { - "loader-utils": "^1.1.0", - "mime": "^2.0.3", - "schema-utils": "^1.0.0" - } - }, - "url-parse": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.6.tgz", - "integrity": "sha512-xj3QdUJ1DttD1LeSfvJlU1eiF1RvBSBfUu8GplFGdUzSO28y5yUtEl7wb//PI4Af6qh0o/K8545vUmucRrfWsw==", - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" - }, - "utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util.promisify": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.1.tgz", - "integrity": "sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "for-each": "^0.3.3", - "has-symbols": "^1.0.1", - "object.getownpropertydescriptors": "^2.1.1" - } - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "vendors": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz", - "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" - }, - "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" - }, - "dependencies": { - "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=" - } - } - }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" - }, - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-3.0.0.tgz", - "integrity": "sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==", - "requires": { - "xml-name-validator": "^4.0.0" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "requires": { - "makeerror": "1.0.12" - } - }, - "watch": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", - "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", - "requires": { - "exec-sh": "^0.2.0", - "minimist": "^1.2.0" - } - }, - "watchpack": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", - "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", - "requires": { - "chokidar": "^3.4.1", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.1" - } - }, - "watchpack-chokidar2": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", - "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", - "optional": true, - "requires": { - "chokidar": "^2.1.8" - }, - "dependencies": { - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "optional": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "optional": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "optional": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "optional": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "optional": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "optional": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "optional": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "optional": true - } - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "optional": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "optional": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "optional": true, - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "optional": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "optional": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "optional": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "optional": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "optional": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "optional": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "optional": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "optional": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "optional": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "optional": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "optional": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "optional": true - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "optional": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "optional": true - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "optional": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - } - } - }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" - }, - "webpack": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.19.1.tgz", - "integrity": "sha512-j7Q/5QqZRqIFXJvC0E59ipLV5Hf6lAnS3ezC3I4HMUybwEDikQBVad5d+IpPtmaQPQArvgUZLXIN6lWijHBn4g==", - "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-module-context": "1.7.6", - "@webassemblyjs/wasm-edit": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6", - "acorn": "^5.6.2", - "acorn-dynamic-import": "^3.0.0", - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0", - "chrome-trace-event": "^1.0.0", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.0", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "micromatch": "^3.1.8", - "mkdirp": "~0.5.0", - "neo-async": "^2.5.0", - "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", - "tapable": "^1.1.0", - "uglifyjs-webpack-plugin": "^1.2.4", - "watchpack": "^1.5.0", - "webpack-sources": "^1.2.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "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" - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "webpack-dev-middleware": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.4.0.tgz", - "integrity": "sha512-Q9Iyc0X9dP9bAsYskAVJ/hmIZZQwf/3Sy4xCAZgL5cUkjZmUZLt4l5HpbST/Pdgjn3u6pE7u5OdGd1apgzRujA==", - "requires": { - "memory-fs": "~0.4.1", - "mime": "^2.3.1", - "range-parser": "^1.0.3", - "webpack-log": "^2.0.0" - } - }, - "webpack-dev-server": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.1.9.tgz", - "integrity": "sha512-fqPkuNalLuc/hRC2QMkVYJkgNmRvxZQo7ykA2e1XRg/tMJm3qY7ZaD6d89/Fqjxtj9bOrn5wZzLD2n84lJdvWg==", - "requires": { - "ansi-html": "0.0.7", - "bonjour": "^3.5.0", - "chokidar": "^2.0.0", - "compression": "^1.5.2", - "connect-history-api-fallback": "^1.3.0", - "debug": "^3.1.0", - "del": "^3.0.0", - "express": "^4.16.2", - "html-entities": "^1.2.0", - "http-proxy-middleware": "~0.18.0", - "import-local": "^2.0.0", - "internal-ip": "^3.0.1", - "ip": "^1.1.5", - "killable": "^1.0.0", - "loglevel": "^1.4.1", - "opn": "^5.1.0", - "portfinder": "^1.0.9", - "schema-utils": "^1.0.0", - "selfsigned": "^1.9.1", - "serve-index": "^1.7.2", - "sockjs": "0.3.19", - "sockjs-client": "1.1.5", - "spdy": "^3.4.1", - "strip-ansi": "^3.0.0", - "supports-color": "^5.1.0", - "webpack-dev-middleware": "3.4.0", - "webpack-log": "^2.0.0", - "yargs": "12.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "decamelize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", - "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", - "requires": { - "xregexp": "4.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.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" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" - } - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "requires": { - "is-descriptor": "^1.0.0" - } - } - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "^3.0.2" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "requires": { - "find-up": "^3.0.0" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "yargs": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", - "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^2.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^10.1.0" - } - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "webpack-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", - "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", - "requires": { - "ansi-colors": "^3.0.0", - "uuid": "^3.3.2" - } - }, - "webpack-manifest-plugin": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.0.4.tgz", - "integrity": "sha512-nejhOHexXDBKQOj/5v5IZSfCeTO3x1Dt1RZEcGfBSul891X/eLIcIVH31gwxPDdsi2Z8LKKFGpM4w9+oTBOSCg==", - "requires": { - "fs-extra": "^7.0.0", - "lodash": ">=3.5 <5", - "tapable": "^1.0.0" - } - }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "websocket": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", - "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", - "requires": { - "bufferutil": "^4.0.1", - "debug": "^2.2.0", - "es5-ext": "^0.10.50", - "typedarray-to-buffer": "^3.1.5", - "utf-8-validate": "^5.0.2", - "yaeti": "^0.0.6" - }, - "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=" - } - } - }, - "websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "requires": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" - }, - "whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "requires": { - "iconv-lite": "0.6.3" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "whatwg-fetch": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", - "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" - }, - "whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==" - }, - "whatwg-url": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-10.0.0.tgz", - "integrity": "sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==", - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "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==" - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - }, - "workbox-background-sync": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-3.6.3.tgz", - "integrity": "sha512-ypLo0B6dces4gSpaslmDg5wuoUWrHHVJfFWwl1udvSylLdXvnrfhFfriCS42SNEe5lsZtcNZF27W/SMzBlva7Q==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-broadcast-cache-update": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-broadcast-cache-update/-/workbox-broadcast-cache-update-3.6.3.tgz", - "integrity": "sha512-pJl4lbClQcvp0SyTiEw0zLSsVYE1RDlCPtpKnpMjxFtu8lCFTAEuVyzxp9w7GF4/b3P4h5nyQ+q7V9mIR7YzGg==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-build": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-3.6.3.tgz", - "integrity": "sha512-w0clZ/pVjL8VXy6GfthefxpEXs0T8uiRuopZSFVQ8ovfbH6c6kUpEh6DcYwm/Y6dyWPiCucdyAZotgjz+nRz8g==", - "requires": { - "babel-runtime": "^6.26.0", - "common-tags": "^1.4.0", - "fs-extra": "^4.0.2", - "glob": "^7.1.2", - "joi": "^11.1.1", - "lodash.template": "^4.4.0", - "pretty-bytes": "^4.0.2", - "stringify-object": "^3.2.2", - "strip-comments": "^1.0.2", - "workbox-background-sync": "^3.6.3", - "workbox-broadcast-cache-update": "^3.6.3", - "workbox-cache-expiration": "^3.6.3", - "workbox-cacheable-response": "^3.6.3", - "workbox-core": "^3.6.3", - "workbox-google-analytics": "^3.6.3", - "workbox-navigation-preload": "^3.6.3", - "workbox-precaching": "^3.6.3", - "workbox-range-requests": "^3.6.3", - "workbox-routing": "^3.6.3", - "workbox-strategies": "^3.6.3", - "workbox-streams": "^3.6.3", - "workbox-sw": "^3.6.3" - }, - "dependencies": { - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - } - } - }, - "workbox-cache-expiration": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-cache-expiration/-/workbox-cache-expiration-3.6.3.tgz", - "integrity": "sha512-+ECNph/6doYx89oopO/UolYdDmQtGUgo8KCgluwBF/RieyA1ZOFKfrSiNjztxOrGJoyBB7raTIOlEEwZ1LaHoA==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-cacheable-response": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-3.6.3.tgz", - "integrity": "sha512-QpmbGA9SLcA7fklBLm06C4zFg577Dt8u3QgLM0eMnnbaVv3rhm4vbmDpBkyTqvgK/Ly8MBDQzlXDtUCswQwqqg==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-core": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-3.6.3.tgz", - "integrity": "sha512-cx9cx0nscPkIWs8Pt98HGrS9/aORuUcSkWjG25GqNWdvD/pSe7/5Oh3BKs0fC+rUshCiyLbxW54q0hA+GqZeSQ==" - }, - "workbox-google-analytics": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-3.6.3.tgz", - "integrity": "sha512-RQBUo/6SXtIaQTRFj4RQZ9e1gAl7D8oS5S+Hi173Kk70/BgJjzPwXpC5A249Jv5YfkCOLMQCeF9A27BiD0b0ig==", - "requires": { - "workbox-background-sync": "^3.6.3", - "workbox-core": "^3.6.3", - "workbox-routing": "^3.6.3", - "workbox-strategies": "^3.6.3" - } - }, - "workbox-navigation-preload": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-3.6.3.tgz", - "integrity": "sha512-dd26xTX16DUu0i+MhqZK/jQXgfIitu0yATM4jhRXEmpMqQ4MxEeNvl2CgjDMOHBnCVMax+CFZQWwxMx/X/PqCw==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-precaching": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-3.6.3.tgz", - "integrity": "sha512-aBqT66BuMFviPTW6IpccZZHzpA8xzvZU2OM1AdhmSlYDXOJyb1+Z6blVD7z2Q8VNtV1UVwQIdImIX+hH3C3PIw==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-range-requests": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-3.6.3.tgz", - "integrity": "sha512-R+yLWQy7D9aRF9yJ3QzwYnGFnGDhMUij4jVBUVtkl67oaVoP1ymZ81AfCmfZro2kpPRI+vmNMfxxW531cqdx8A==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-routing": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-3.6.3.tgz", - "integrity": "sha512-bX20i95OKXXQovXhFOViOK63HYmXvsIwZXKWbSpVeKToxMrp0G/6LZXnhg82ijj/S5yhKNRf9LeGDzaqxzAwMQ==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-strategies": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-3.6.3.tgz", - "integrity": "sha512-Pg5eulqeKet2y8j73Yw6xTgLdElktcWExGkzDVCGqfV9JCvnGuEpz5eVsCIK70+k4oJcBCin9qEg3g3CwEIH3g==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-streams": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-3.6.3.tgz", - "integrity": "sha512-rqDuS4duj+3aZUYI1LsrD2t9hHOjwPqnUIfrXSOxSVjVn83W2MisDF2Bj+dFUZv4GalL9xqErcFW++9gH+Z27w==", - "requires": { - "workbox-core": "^3.6.3" - } - }, - "workbox-sw": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-3.6.3.tgz", - "integrity": "sha512-IQOUi+RLhvYCiv80RP23KBW/NTtIvzvjex28B8NW1jOm+iV4VIu3VXKXTA6er5/wjjuhmtB28qEAUqADLAyOSg==" - }, - "workbox-webpack-plugin": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-3.6.2.tgz", - "integrity": "sha512-FGSkcaiMDM41uTGkYf7O6hf2W7UvkNc+iUIltfGiRp+qeQfXKOOh5fJCz+a6AFkeuGELSSYROsQRuOqX8LytcQ==", - "requires": { - "babel-runtime": "^6.26.0", - "json-stable-stringify": "^1.0.1", - "workbox-build": "^3.6.2" - } - }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "requires": { - "mkdirp": "^0.5.1" - } - }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==" - }, - "xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==" - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" - }, - "xregexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", - "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" - }, - "yaeti": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", - "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=" - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "yargs": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", - "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.1.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - }, - "dependencies": { - "y18n": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" - } - } - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "requires": { - "camelcase": "^4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - } - } - } - } -} diff --git a/src/tools/nova_dash/client/package.json b/src/tools/nova_dash/client/package.json deleted file mode 100755 index 2067942e5..000000000 --- a/src/tools/nova_dash/client/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "nova-dash-client", - "version": "1.0.0", - "description": "", - "keywords": [], - "main": "src/index.js", - "dependencies": { - "react": "16.8.0", - "react-burger-menu": "^3.0.6", - "react-dom": "16.8.0", - "react-router-dom": "^6.2.2", - "react-scripts": "2.0.3", - "regl-worldview": "latest", - "websocket": "^1.0.34" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" - }, - "browser": { - "fs": false, - "path": false, - "os": false - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ] -} diff --git a/src/tools/nova_dash/client/public/index.html b/src/tools/nova_dash/client/public/index.html deleted file mode 100755 index 42ae2d2dc..000000000 --- a/src/tools/nova_dash/client/public/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - React App - - - - -
        - - - - \ No newline at end of file diff --git a/src/tools/nova_dash/client/src/Console.js b/src/tools/nova_dash/client/src/Console.js deleted file mode 100755 index ed43ab5d6..000000000 --- a/src/tools/nova_dash/client/src/Console.js +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useState } from "react"; -import { w3cwebsocket as W3CWebSocket } from "websocket"; - -// New websocket client -const client = new W3CWebSocket('ws://localhost:3030'); - -export default function Example() { - let messages = []; - - const getElement = (id) => document.getElementById(id); - - // Add message when string inputted - const addMessage = (message) => { - const pTag = document.createElement('p'); // Create paragraph element - pTag.appendChild(document.createTextNode("| " + message)); // Create new text node with message - getElement('messages').appendChild(pTag); // Find message element and put new tag in holder - }; - - client.onopen = () => { // When client establishes connection to server - console.log('Socket Client Connected'); - }; - - client.onmessage = (message) => { // On client message - const data = JSON.parse(message.data); // Parse json event for data (if multiple messages) - if (data[0] === "Message") { - const messages = data[1]; // Parse json event for data (if multiple messages) - messages.forEach(addMessage); // Create message out of non-json objects from messages array - } - }; - - return( - <> -

        Nova | Dash

        - -
        - - ); -} \ No newline at end of file diff --git a/src/tools/nova_dash/client/src/Worldview.js b/src/tools/nova_dash/client/src/Worldview.js deleted file mode 100755 index 2d0b3b90c..000000000 --- a/src/tools/nova_dash/client/src/Worldview.js +++ /dev/null @@ -1,188 +0,0 @@ -import React, { useState } from "react"; -import Worldview, { Grid, Text, Cubes, Lines, Axes } from "regl-worldview"; -import { w3cwebsocket as W3CWebSocket } from "websocket"; - -// New websocket client -const client = new W3CWebSocket('ws://localhost:3030'); - -function returnObjects(message) { // Creates objects from converted message.data entry - let cube = { // Cube object - id: message.id, - depth: { - enable: true, - mask: true, - }, - blend: { - enable: true, - func: { - srcRGB: "src alpha", - srcAlpha: 1, - dstRGB: "one minus src alpha", - dstAlpha: 1, - }, - }, - pose: { - orientation: { - x: message.pose.orientation.x, - y: message.pose.orientation.y, - z: message.pose.orientation.z, - w: message.pose.orientation.w }, - position: { - x: message.pose.position.x, - y: message.pose.position.y, - z: message.pose.position.z - }, - }, - scale: { - x: message.scale.x, - y: message.scale.y, - z: message.scale.z - }, - color: { - r: message.color.r, - g: message.color.g, - b: message.color.b, - a: message.color.a - }, - } - - let text = { // Text object - id: message.id, - name: message.name, - text: "[" + message.id + "] " + message.name, - color: { r: 1, g: 1, b: 1, a: 1 }, - pose: { - orientation: { - x: message.pose.orientation.x, - y: message.pose.orientation.y, - z: message.pose.orientation.z, - w: message.pose.orientation.w }, - position: { - x: message.pose.position.x, - y: message.pose.position.y, - z: message.pose.position.z - }, - }, - scale: { - x: message.scale.x, - y: message.scale.y, - z: message.scale.z - }, - } - - // Bounding boxes initial positions - let scale = message.scale; - const p0 = [-scale.x / 2, -scale.y / 2, -scale.z / 2]; - const p1 = [scale.x / 2, -scale.y / 2, -scale.z / 2]; - const p2 = [scale.x / 2, scale.y / 2, -scale.z / 2]; - const p3 = [-scale.x / 2, scale.y / 2, -scale.z / 2]; - const p4 = [-scale.x / 2, -scale.y / 2, scale.z / 2]; - const p5 = [scale.x / 2, -scale.y / 2, scale.z / 2]; - const p6 = [scale.x / 2, scale.y / 2, scale.z / 2]; - const p7 = [-scale.x / 2, scale.y / 2, scale.z / 2]; - - let lines = { // Bounding line object - pose: message.pose, - primitive: "lines", - scale: { x: 0.2, y: 0.2, z: 0.2 }, - points: [ - // bottom - p0, - p1, - p1, - p2, - p2, - p3, - p3, - p0, - // top - p4, - p5, - p5, - p6, - p6, - p7, - p7, - p4, - // around - p0, - p4, - p1, - p5, - p2, - p6, - p3, - p7, - ], - color: { r: 1, g: 0, b: 0, a: 1 }, - }; - - return [cube,text,lines]; -} - -export default function Example() { - // Marker and text tables - let markers = []; - let texts = []; - let lines = []; - - function createCube(message){ - // Check if object already exists - - let found = false; - let foundKey = 0; - // Disable error for unused value next line - // eslint-disable-next-line - - // Check if object already exists - for (const [key, value] of Object.entries(markers)) { - if(markers[key].id === message.id) { - found = true; - foundKey = key; - } - } - - // Create object with box, text and line - let objs = returnObjects(message); - let cube = objs[0]; - let text = objs[1]; - let line = objs[2]; - - if(found === true) { // If object already exists, replace current object with new object - markers[foundKey] = cube; - texts[foundKey] = text; - lines[foundKey] = line; - - }else{ // Otherwise add the new object to the table - markers.push(cube); - texts.push(text); - lines.push(line); - } - } - - client.onopen = () => { // When client establishes connection to server - console.log('Socket Client Connected'); - }; - - client.onmessage = (message) => { // On client message - const data = JSON.parse(message.data); - if(data[0] === "Object") { - const newData = data[1]; - for (var i = 0; i < newData.length; i++) { - console.log( newData[i] ); - createCube( newData[i] ); - } - } - }; - - return ( - - - {texts} - {markers} - {lines} - - - - ); -} diff --git a/src/tools/nova_dash/client/src/index.js b/src/tools/nova_dash/client/src/index.js deleted file mode 100755 index a6110ed9f..000000000 --- a/src/tools/nova_dash/client/src/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import Worldview from "./Worldview"; -import Console from "./Console" -import SideBar from "./sidebar" - -import './styles.css'; - -import { - BrowserRouter as Router, - Routes, - Route -} from "react-router-dom"; - -function App() { - return ( - -
        - - - - }/> - }/> - - -
        -
        - ); -} - -const rootElement = document.getElementById("root"); -ReactDOM.render(, rootElement); \ No newline at end of file diff --git a/src/tools/nova_dash/client/src/sidebar.js b/src/tools/nova_dash/client/src/sidebar.js deleted file mode 100755 index 99795cf1f..000000000 --- a/src/tools/nova_dash/client/src/sidebar.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { slide as Menu } from 'react-burger-menu'; - -export default props => { - return ( - - - 3D View - - - - Console View - - - ); -}; \ No newline at end of file diff --git a/src/tools/nova_dash/client/src/styles.css b/src/tools/nova_dash/client/src/styles.css deleted file mode 100755 index 632cafb5c..000000000 --- a/src/tools/nova_dash/client/src/styles.css +++ /dev/null @@ -1,76 +0,0 @@ -html, - -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} - -#App { - font-family: sans-serif; - height: 100vh; -} - -#page-wrap { - text-align: center; - overflow: auto; -} - -.bm-item { - display: inline-block; - text-decoration: none; - margin-bottom: 10px; - color: #d1d1d1; - transition: color 0.2s; -} - -.bm-item:hover { - color: white; -} - -.bm-burger-button { - position: fixed; - width: 36px; - height: 30px; - left: 36px; - top: 36px; -} - -.bm-burger-bars { - background: #373a47; -} - -.bm-cross-button { - height: 24px; - width: 24px; -} - -.bm-cross { - background: #bdc3c7; -} - -.bm-menu { - background: #373a47; - padding: 2.5em 1.5em 0; - font-size: 1.15em; -} - -.bm-morph-shape { - fill: #373a47; -} - -.bm-item-list { - color: #b8b7ad; -} - -.bm-overlay { - background: rgba(0, 0, 0, 0.3); -} \ No newline at end of file diff --git a/src/tools/nova_dash/client/webpack.config.dev.js b/src/tools/nova_dash/client/webpack.config.dev.js deleted file mode 100755 index 98d50984d..000000000 --- a/src/tools/nova_dash/client/webpack.config.dev.js +++ /dev/null @@ -1,441 +0,0 @@ -// @remove-on-eject-begin -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -// @remove-on-eject-end -'use strict'; - -const path = require('path'); -const webpack = require('webpack'); -const PnpWebpackPlugin = require('pnp-webpack-plugin'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); -const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); -const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); -const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); -const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent'); -const getClientEnvironment = require('./env'); -const paths = require('./paths'); -const ManifestPlugin = require('webpack-manifest-plugin'); -const getCacheIdentifier = require('react-dev-utils/getCacheIdentifier'); -const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin'); - -// Webpack uses `publicPath` to determine where the app is being served from. -// In development, we always serve from the root. This makes config easier. -const publicPath = '/'; -// `publicUrl` is just like `publicPath`, but we will provide it to our app -// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. -// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz. -const publicUrl = ''; -// Get environment variables to inject into our app. -const env = getClientEnvironment(publicUrl); - -// style files regexes -const cssRegex = /\.css$/; -const cssModuleRegex = /\.module\.css$/; -const sassRegex = /\.(scss|sass)$/; -const sassModuleRegex = /\.module\.(scss|sass)$/; - -// common function to get style loaders -const getStyleLoaders = (cssOptions, preProcessor) => { - const loaders = [ - require.resolve('style-loader'), - { - loader: require.resolve('css-loader'), - options: cssOptions, - }, - { - // Options for PostCSS as we reference these options twice - // Adds vendor prefixing based on your specified browser support in - // package.json - loader: require.resolve('postcss-loader'), - options: { - // Necessary for external CSS imports to work - // https://github.com/facebook/create-react-app/issues/2677 - ident: 'postcss', - plugins: () => [ - require('postcss-flexbugs-fixes'), - require('postcss-preset-env')({ - autoprefixer: { - flexbox: 'no-2009', - }, - stage: 3, - }), - ], - }, - }, - ]; - if (preProcessor) { - loaders.push(require.resolve(preProcessor)); - } - return loaders; -}; - -// This is the development configuration. -// It is focused on developer experience and fast rebuilds. -// The production configuration is different and lives in a separate file. -module.exports = { - mode: 'development', - // You may want 'eval' instead if you prefer to see the compiled output in DevTools. - // See the discussion in https://github.com/facebook/create-react-app/issues/343 - devtool: 'cheap-module-source-map', - // These are the "entry points" to our application. - // This means they will be the "root" imports that are included in JS bundle. - entry: [ - // Include an alternative client for WebpackDevServer. A client's job is to - // connect to WebpackDevServer by a socket and get notified about changes. - // When you save a file, the client will either apply hot updates (in case - // of CSS changes), or refresh the page (in case of JS changes). When you - // make a syntax error, this client will display a syntax error overlay. - // Note: instead of the default WebpackDevServer client, we use a custom one - // to bring better experience for Create React App users. You can replace - // the line below with these two lines if you prefer the stock client: - // require.resolve('webpack-dev-server/client') + '?/', - // require.resolve('webpack/hot/dev-server'), - require.resolve('react-dev-utils/webpackHotDevClient'), - // Finally, this is your app's code: - paths.appIndexJs, - // We include the app code last so that if there is a runtime error during - // initialization, it doesn't blow up the WebpackDevServer client, and - // changing JS code would still trigger a refresh. - ], - output: { - // Add /* filename */ comments to generated require()s in the output. - pathinfo: true, - // This does not produce a real file. It's just the virtual path that is - // served by WebpackDevServer in development. This is the JS bundle - // containing code from all our entry points, and the Webpack runtime. - filename: 'static/js/bundle.js', - // There are also additional JS chunk files if you use code splitting. - chunkFilename: 'static/js/[name].chunk.js', - // This is the URL that app is served from. We use "/" in development. - publicPath: publicPath, - // Point sourcemap entries to original disk location (format as URL on Windows) - devtoolModuleFilenameTemplate: info => - path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'), - }, - optimization: { - // Automatically split vendor and commons - // https://twitter.com/wSokra/status/969633336732905474 - // https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366 - splitChunks: { - chunks: 'all', - name: false, - }, - // Keep the runtime chunk seperated to enable long term caching - // https://twitter.com/wSokra/status/969679223278505985 - runtimeChunk: true, - }, - resolve: { - // This allows you to set a fallback for where Webpack should look for modules. - // We placed these paths second because we want `node_modules` to "win" - // if there are any conflicts. This matches Node resolution mechanism. - // https://github.com/facebook/create-react-app/issues/253 - modules: ['node_modules'].concat( - // It is guaranteed to exist because we tweak it in `env.js` - process.env.NODE_PATH.split(path.delimiter).filter(Boolean) - ), - // These are the reasonable defaults supported by the Node ecosystem. - // We also include JSX as a common component filename extension to support - // some tools, although we do not recommend using it, see: - // https://github.com/facebook/create-react-app/issues/290 - // `web` extension prefixes have been added for better support - // for React Native Web. - extensions: ['.web.js', '.js', '.json', '.web.jsx', '.jsx'], - alias: { - // Support React Native Web - // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ - 'react-native': 'react-native-web', - }, - plugins: [ - // Adds support for installing with Plug'n'Play, leading to faster installs and adding - // guards against forgotten dependencies and such. - PnpWebpackPlugin, - // Prevents users from importing files from outside of src/ (or node_modules/). - // This often causes confusion because we only process files within src/ with babel. - // To fix this, we prevent you from importing files out of src/ -- if you'd like to, - // please link the files into your node_modules/ and let module-resolution kick in. - // Make sure your source files are compiled, as they will not be processed in any way. - new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]), - ], - }, - resolveLoader: { - plugins: [ - // Also related to Plug'n'Play, but this time it tells Webpack to load its loaders - // from the current package. - PnpWebpackPlugin.moduleLoader(module), - ], - }, - module: { - strictExportPresence: true, - rules: [ - // Disable require.ensure as it's not a standard language feature. - { parser: { requireEnsure: false } }, - - // for worldview - { - test: /draco_decoder\.wasm$/, - type: 'javascript/auto', - loader: 'file-loader', - options: { - publicPath: "dist/" - } - }, - - // First, run the linter. - // It's important to do this before Babel processes the JS. - { - test: /\.(js|jsx)$/, - enforce: 'pre', - use: [ - { - options: { - formatter: require.resolve('react-dev-utils/eslintFormatter'), - eslintPath: require.resolve('eslint'), - // @remove-on-eject-begin - baseConfig: { - extends: [require.resolve('eslint-config-react-app')], - settings: { react: { version: '999.999.999' } }, - }, - ignore: false, - useEslintrc: false, - // @remove-on-eject-end - }, - loader: require.resolve('eslint-loader'), - }, - ], - include: paths.appSrc, - }, - { - // `mjs` support is still in its infancy in the ecosystem, so we don't - // support it. - // Modules who define their `browser` or `module` key as `mjs` force - // the use of this extension, so we need to tell webpack to fall back - // to auto mode (ES Module interop, allows ESM to import CommonJS). - test: /\.mjs$/, - include: /node_modules/, - type: 'javascript/auto', - }, - { - // "oneOf" will traverse all following loaders until one will - // match the requirements. When no loader matches it will fall - // back to the "file" loader at the end of the loader list. - oneOf: [ - // "url" loader works like "file" loader except that it embeds assets - // smaller than specified limit in bytes as data URLs to avoid requests. - // A missing `test` is equivalent to a match. - { - test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], - loader: require.resolve('url-loader'), - options: { - limit: 10000, - name: 'static/media/[name].[hash:8].[ext]', - }, - }, - // Process application JS with Babel. - // The preset includes JSX, Flow, and some ESnext features. - { - test: /\.(js|jsx)$/, - include: paths.appSrc, - loader: require.resolve('babel-loader'), - options: { - customize: require.resolve( - 'babel-preset-react-app/webpack-overrides' - ), - // @remove-on-eject-begin - babelrc: false, - configFile: false, - presets: [require.resolve('babel-preset-react-app')], - // Make sure we have a unique cache identifier, erring on the - // side of caution. - // We remove this when the user ejects because the default - // is sane and uses Babel options. Instead of options, we use - // the react-scripts and babel-preset-react-app versions. - cacheIdentifier: getCacheIdentifier('development', [ - 'babel-plugin-named-asset-import', - 'babel-preset-react-app', - 'react-dev-utils', - 'react-scripts', - ]), - // @remove-on-eject-end - plugins: [ - [ - require.resolve('babel-plugin-named-asset-import'), - { - loaderMap: { - svg: { - ReactComponent: '@svgr/webpack?-prettier,-svgo![path]', - }, - }, - }, - ], - ], - // This is a feature of `babel-loader` for webpack (not Babel itself). - // It enables caching results in ./node_modules/.cache/babel-loader/ - // directory for faster rebuilds. - cacheDirectory: true, - // Don't waste time on Gzipping the cache - cacheCompression: false, - }, - }, - // Process any JS outside of the app with Babel. - // Unlike the application JS, we only compile the standard ES features. - { - test: /\.js$/, - exclude: /@babel(?:\/|\\{1,2})runtime/, - loader: require.resolve('babel-loader'), - options: { - babelrc: false, - configFile: false, - compact: false, - presets: [ - [ - require.resolve('babel-preset-react-app/dependencies'), - { helpers: true }, - ], - ], - cacheDirectory: true, - // Don't waste time on Gzipping the cache - cacheCompression: false, - // @remove-on-eject-begin - cacheIdentifier: getCacheIdentifier('development', [ - 'babel-plugin-named-asset-import', - 'babel-preset-react-app', - 'react-dev-utils', - 'react-scripts', - ]), - // @remove-on-eject-end - // If an error happens in a package, it's possible to be - // because it was compiled. Thus, we don't want the browser - // debugger to show the original code. Instead, the code - // being evaluated would be much more helpful. - sourceMaps: false, - }, - }, - // "postcss" loader applies autoprefixer to our CSS. - // "css" loader resolves paths in CSS and adds assets as dependencies. - // "style" loader turns CSS into JS modules that inject