From 9be2d18d02a7079981160939d1b91c0c81fd0179 Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Mon, 6 Jan 2020 14:58:33 +0800 Subject: [PATCH 01/32] [ZEPPELIN-4414]. Upgrade thrift to 0.13 ### What is this PR for? This is a straightforward PR which upgrade thrift to 0.13 ### What type of PR is it? [Improvement ] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4144 ### How should this be tested? * CI pass ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3587 from zjffdu/ZEPPELIN-4414 and squashes the following commits: bb086e27a [Jeff Zhang] [ZEPPELIN-4414]. Upgrade thrift to 0.13 --- pom.xml | 8 +++++++- .../zeppelin/interpreter/thrift/AngularObjectId.java | 4 ++-- .../zeppelin/interpreter/thrift/AppOutputAppendEvent.java | 4 ++-- .../zeppelin/interpreter/thrift/AppOutputUpdateEvent.java | 4 ++-- .../zeppelin/interpreter/thrift/AppStatusUpdateEvent.java | 4 ++-- .../interpreter/thrift/InterpreterCompletion.java | 4 ++-- .../zeppelin/interpreter/thrift/OutputAppendEvent.java | 4 ++-- .../zeppelin/interpreter/thrift/OutputUpdateAllEvent.java | 4 ++-- .../zeppelin/interpreter/thrift/OutputUpdateEvent.java | 4 ++-- .../apache/zeppelin/interpreter/thrift/ParagraphInfo.java | 4 ++-- .../apache/zeppelin/interpreter/thrift/RegisterInfo.java | 4 ++-- .../interpreter/thrift/RemoteApplicationResult.java | 4 ++-- .../interpreter/thrift/RemoteInterpreterContext.java | 4 ++-- .../interpreter/thrift/RemoteInterpreterEvent.java | 4 ++-- .../interpreter/thrift/RemoteInterpreterEventService.java | 4 ++-- .../interpreter/thrift/RemoteInterpreterEventType.java | 4 ++-- .../interpreter/thrift/RemoteInterpreterResult.java | 4 ++-- .../thrift/RemoteInterpreterResultMessage.java | 4 ++-- .../interpreter/thrift/RemoteInterpreterService.java | 4 ++-- .../zeppelin/interpreter/thrift/RunParagraphsEvent.java | 4 ++-- .../zeppelin/interpreter/thrift/ServiceException.java | 4 ++-- 21 files changed, 47 insertions(+), 41 deletions(-) diff --git a/pom.xml b/pom.xml index bdcebe0118d..7ef1665eabe 100644 --- a/pom.xml +++ b/pom.xml @@ -116,7 +116,7 @@ 1.7.10 1.2.17 - 0.12.0 + 0.13.0 2.2 0.2.1 9.4.18.v20190429 @@ -194,6 +194,12 @@ org.apache.thrift libthrift ${libthrift.version} + + + javax.annotation + javax.annotation-api + + diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java index 7aa2081f3c2..fc1004a30c5 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class AngularObjectId implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AngularObjectId"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java index 38cff035212..723754a0bb8 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class AppOutputAppendEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputAppendEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java index f14b70190c4..0d72b31597c 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class AppOutputUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java index 90e6b0d1b6f..dfc5a530344 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class AppStatusUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppStatusUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java index 688daad2d99..6d0c8f5c383 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class InterpreterCompletion implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("InterpreterCompletion"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java index 49e5d742b53..1a8fc2e764a 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class OutputAppendEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputAppendEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java index 6b9c81c03f7..0df11968994 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class OutputUpdateAllEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateAllEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java index df163d64c56..f4ac7d9cce1 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class OutputUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java index 59e73405e2c..a2acfc13f36 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class ParagraphInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ParagraphInfo"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java index 8cd7b2e1a5e..7f40f5a8a96 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RegisterInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RegisterInfo"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java index b38b2c4df31..2965912084f 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RemoteApplicationResult implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteApplicationResult"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java index ddc1d3c353c..724b9dbd928 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RemoteInterpreterContext implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterContext"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java index 6fd85d5fae6..66f619977d8 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RemoteInterpreterEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java index 8ef10331013..daea0190054 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RemoteInterpreterEventService { public interface Iface { diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java index 47a2bce5562..e397607565e 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public enum RemoteInterpreterEventType implements org.apache.thrift.TEnum { NO_OP(1), ANGULAR_OBJECT_ADD(2), diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java index ea8f808af64..4f578eec968 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RemoteInterpreterResult implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResult"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java index 877d22d8bdf..8cbc0546f54 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RemoteInterpreterResultMessage implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResultMessage"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java index 6804d1590f2..f7d3cb3e831 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RemoteInterpreterService { public interface Iface { diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java index cda3c896789..8eba9c9af06 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class RunParagraphsEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RunParagraphsEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java index fc9ac317862..039043d02d1 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java @@ -16,7 +16,7 @@ * limitations under the License. */ /** - * Autogenerated by Thrift Compiler (0.12.0) + * Autogenerated by Thrift Compiler (0.13.0) * * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING * @generated @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.12.0)", date = "2019-06-10") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") public class ServiceException extends org.apache.thrift.TException implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ServiceException"); From f08c75ceacacc819ebf51582449ac4eb498e6279 Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Sat, 9 Nov 2019 21:51:04 +0800 Subject: [PATCH 02/32] [ZEPPELIN-4440]. Update spark document ### What is this PR for? This PR refine the spark document. ### What type of PR is it? [Documentation] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4440 ### How should this be tested? * CI pass ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3577 from zjffdu/ZEPPELIN-4440 and squashes the following commits: 88f7ef725 [Jeff Zhang] [ZEPPELIN-4440]. Update spark document --- .../img/docs-img/spark_SPARK_HOME16.png | Bin 0 -> 123514 bytes .../img/docs-img/spark_SPARK_HOME24.png | Bin 0 -> 122833 bytes .../docs-img/spark_inline_configuration.png | Bin 0 -> 38073 bytes .../img/docs-img/spark_user_impersonation.png | Bin 0 -> 68387 bytes docs/interpreter/spark.md | 335 ++++++++++++------ docs/usage/interpreter/overview.md | 2 +- .../main/resources/interpreter-setting.json | 125 ++++--- 7 files changed, 301 insertions(+), 161 deletions(-) create mode 100644 docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME16.png create mode 100644 docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME24.png create mode 100644 docs/assets/themes/zeppelin/img/docs-img/spark_inline_configuration.png create mode 100644 docs/assets/themes/zeppelin/img/docs-img/spark_user_impersonation.png diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME16.png b/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME16.png new file mode 100644 index 0000000000000000000000000000000000000000..f925d47c17e076a9b3056096408cef47b350cb45 GIT binary patch literal 123514 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 MFT6g_-^@7vHy4|;CjbBd literal 0 HcmV?d00001 diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME24.png b/docs/assets/themes/zeppelin/img/docs-img/spark_SPARK_HOME24.png new file mode 100644 index 0000000000000000000000000000000000000000..0eaa063d608a9e09721091e47f675574bddacf48 GIT binary patch literal 122833 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 literal 0 HcmV?d00001 diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_inline_configuration.png b/docs/assets/themes/zeppelin/img/docs-img/spark_inline_configuration.png new file mode 100644 index 0000000000000000000000000000000000000000..c02785b62b84dbea105e852993dd2c193677cbe9 GIT binary patch literal 38073 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 A6aWAK literal 0 HcmV?d00001 diff --git a/docs/assets/themes/zeppelin/img/docs-img/spark_user_impersonation.png b/docs/assets/themes/zeppelin/img/docs-img/spark_user_impersonation.png new file mode 100644 index 0000000000000000000000000000000000000000..f16f402f811dbd573a48ea88d8a6fc37cc4ae5af GIT binary patch literal 68387 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 Cvtw}p literal 0 HcmV?d00001 diff --git a/docs/interpreter/spark.md b/docs/interpreter/spark.md index bd50cb017b9..ef799593d26 100644 --- a/docs/interpreter/spark.md +++ b/docs/interpreter/spark.md @@ -37,18 +37,18 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist %spark SparkInterpreter - Creates a SparkContext and provides a Scala environment - - - %spark.kotlin - KotlinSparkInterpreter - Provides a Kotlin environment + Creates a SparkContext/SparkSession and provides a Scala environment %spark.pyspark PySparkInterpreter Provides a Python environment + + %spark.ipyspark + IPySparkInterpreter + Provides a IPython environment + %spark.r SparkRInterpreter @@ -60,9 +60,9 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist Provides a SQL environment - %spark.dep - DepInterpreter - Dependency loader + %spark.kotlin + KotlinSparkInterpreter + Provides a Kotlin environment @@ -76,42 +76,58 @@ You can also set other Spark properties which are not listed in the table. For a Description - args + `SPARK_HOME` - Spark commandline args - + Location of spark distribution + + master local[*] - Spark master uri.
ex) spark://masterhost:7077 + Spark master uri.
e.g. spark://master_host:7077 spark.app.name Zeppelin The name of spark application. - spark.cores.max - - Total number of cores to use.
Empty value uses all available core. + spark.driver.cores + 1 + Number of cores to use for the driver process, only in cluster mode. - spark.executor.memory + spark.driver.memory 1g - Executor memory per worker instance.
ex) 512m, 32g + Amount of memory to use for the driver process, i.e. where SparkContext is initialized, in the same format as JVM memory strings with a size unit suffix ("k", "m", "g" or "t") (e.g. 512m, 2g). - zeppelin.dep.additionalRemoteRepository - spark-packages,
http://dl.bintray.com/spark-packages/maven,
false; - A list of `id,remote-repository-URL,is-snapshot;`
for each remote repository. + spark.executor.cores + 1 + The number of cores to use on each executor - zeppelin.dep.localrepo - local-repo - Local repository for dependency loader + spark.executor.memory + 1g + Executor memory per worker instance.
e.g. 512m, 32g + + + spark.files + + Comma-separated list of files to be placed in the working directory of each executor. Globs are allowed. + + + spark.jars + + Comma-separated list of jars to include on the driver and executor classpaths. Globs are allowed. + + + spark.jars.packages + + Comma-separated list of Maven coordinates of jars to include on the driver and executor classpaths. The coordinates should be groupId:artifactId:version. If spark.jars.ivySettings is given artifacts will be resolved according to the configuration in the file, otherwise artifacts will be searched for in the local maven repo, then maven central and finally any additional remote repositories given by the command-line option --repositories. `PYSPARK_PYTHON` python - Python binary executable to use for PySpark in both driver and workers (default is python). + Python binary executable to use for PySpark in both driver and executors (default is python). Property spark.pyspark.python take precedence if it is set @@ -120,6 +136,16 @@ You can also set other Spark properties which are not listed in the table. For a Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). Property spark.pyspark.driver.python take precedence if it is set + + zeppelin.pyspark.useIPython + false + Whether use IPython when the ipython prerequisites are met in `%spark.pyspark` + + + zeppelin.R.cmd + R + R binary executable path. + zeppelin.spark.concurrentSQL false @@ -133,22 +159,17 @@ You can also set other Spark properties which are not listed in the table. For a zeppelin.spark.maxResult 1000 - Max number of Spark SQL result to display. + Max number rows of Spark SQL result to display. zeppelin.spark.printREPLOutput true - Print REPL output + Print scala REPL output zeppelin.spark.useHiveContext true - Use HiveContext instead of SQLContext if it is true. - - - zeppelin.spark.importImplicit - true - Import implicits, UDF collection, and sql if set true. + Use HiveContext instead of SQLContext if it is true. Enable hive for SparkSession zeppelin.spark.enableSupportedVersionCheck @@ -158,47 +179,68 @@ You can also set other Spark properties which are not listed in the table. For a zeppelin.spark.sql.interpolation false - Enable ZeppelinContext variable interpolation into paragraph text + Enable ZeppelinContext variable interpolation into spark sql zeppelin.spark.uiWebUrl Overrides Spark UI default URL. Value should be a full URL (ex: http://{hostName}/{uniquePath} - zeppelin.spark.scala.color - true - Whether to enable color output of spark scala interpreter - Without any configuration, Spark interpreter works out of box in local mode. But if you want to connect to your Spark cluster, you'll need to follow below two simple steps. -### 1. Export SPARK_HOME -In `conf/zeppelin-env.sh`, export `SPARK_HOME` environment variable with your Spark installation path. +### Export SPARK_HOME -For example, +There are several options for setting `SPARK_HOME`. + +* Set `SPARK_HOME` in `zeppelin-env.sh` +* Set `SPARK_HOME` in Interpreter setting page +* Set `SPARK_HOME` via [inline generic configuration](../usage/interpreter/overview.html#inline-generic-confinterpreter) + +#### 1. Set `SPARK_HOME` in `zeppelin-env.sh` + +If you work with only one version of spark, then you can set `SPARK_HOME` in `zeppelin-env.sh` because any setting in `zeppelin-env.sh` is globally applied. + +e.g. ```bash export SPARK_HOME=/usr/lib/spark ``` -You can optionally set more environment variables +You can optionally set more environment variables in `zeppelin-env.sh` ```bash # set hadoop conf dir export HADOOP_CONF_DIR=/usr/lib/hadoop -# set options to pass spark-submit command -export SPARK_SUBMIT_OPTIONS="--packages com.databricks:spark-csv_2.10:1.2.0" - -# extra classpath. e.g. set classpath for hive-site.xml -export ZEPPELIN_INTP_CLASSPATH_OVERRIDES=/etc/hive/conf ``` -For Windows, ensure you have `winutils.exe` in `%HADOOP_HOME%\bin`. Please see [Problems running Hadoop on Windows](https://wiki.apache.org/hadoop/WindowsProblems) for the details. -### 2. Set master in Interpreter menu -After start Zeppelin, go to **Interpreter** menu and edit **master** property in your Spark interpreter setting. The value may vary depending on your Spark cluster deployment type. +#### 2. Set `SPARK_HOME` in Interpreter setting page + +If you want to use multiple versions of spark, then you need create multiple spark interpreters and set `SPARK_HOME` for each of them. e.g. +Create a new spark interpreter `spark24` for spark 2.4 and set `SPARK_HOME` in interpreter setting page +
+ +
+ +Create a new spark interpreter `spark16` for spark 1.6 and set `SPARK_HOME` in interpreter setting page +
+ +
+ + +#### 3. Set `SPARK_HOME` via [inline generic configuration](../usage/interpreter/overview.html#inline-generic-confinterpreter) + +Besides setting `SPARK_HOME` in interpreter setting page, you can also use inline generic configuration to put the +configuration with code together for more flexibility. e.g. +
+ +
+ +### Set master in Interpreter menu +After starting Zeppelin, go to **Interpreter** menu and edit **master** property in your Spark interpreter setting. The value may vary depending on your Spark cluster deployment type. For example, @@ -213,93 +255,132 @@ For the further information about Spark & Zeppelin version compatibility, please > Note that without exporting `SPARK_HOME`, it's running in local mode with included version of Spark. The included version may vary depending on the build profile. -### 3. Yarn mode -Zeppelin support both yarn client and yarn cluster mode (yarn cluster mode is supported from 0.8.0). For yarn mode, you must specify `SPARK_HOME` & `HADOOP_CONF_DIR`. -You can either specify them in `zeppelin-env.sh`, or in interpreter setting page. Specifying them in `zeppelin-env.sh` means you can use only one version of `spark` & `hadoop`. Specifying them -in interpreter setting page means you can use multiple versions of `spark` & `hadoop` in one zeppelin instance. - -### 4. New Version of SparkInterpreter -Starting from 0.9, we totally removed the old spark interpreter implementation, and make the new spark interpreter as the official spark interpreter. - ## SparkContext, SQLContext, SparkSession, ZeppelinContext -SparkContext, SQLContext and ZeppelinContext are automatically created and exposed as variable names `sc`, `sqlContext` and `z`, respectively, in Scala, Kotlin, Python and R environments. -Staring from 0.6.1 SparkSession is available as variable `spark` when you are using Spark 2.x. - -> Note that Scala/Python/R environment shares the same SparkContext, SQLContext and ZeppelinContext instance. -
+SparkContext, SQLContext, SparkSession (for spark 2.x) and ZeppelinContext are automatically created and exposed as variable names `sc`, `sqlContext`, `spark` and `z`, respectively, in Scala, Kotlin, Python and R environments. -### How to pass property to SparkConf -There're 2 kinds of properties that would be passed to SparkConf +> Note that Scala/Python/R environment shares the same SparkContext, SQLContext, SparkSession and ZeppelinContext instance. - * Standard spark property (prefix with `spark.`). e.g. `spark.executor.memory` will be passed to `SparkConf` - * Non-standard spark property (prefix with `zeppelin.spark.`). e.g. `zeppelin.spark.property_1`, `property_1` will be passed to `SparkConf` +## YARN Mode +Zeppelin support both yarn client and yarn cluster mode (yarn cluster mode is supported from 0.8.0). For yarn mode, you must specify `SPARK_HOME` & `HADOOP_CONF_DIR`. +Usually you only have one hadoop cluster, so you can set `HADOOP_CONF_DIR` in `zeppelin-env.sh` which is applied to all spark interpreters. If you want to use spark against multiple hadoop cluster, then you need to define +`HADOOP_CONF_DIR` in interpreter setting or via inline generic configuration. ## Dependency Management -For spark interpreter, you should not use Zeppelin's [Dependency Management](../usage/interpreter/dependency_management.html) for managing -third party dependencies, (`%spark.dep` also is not the recommended approach starting from Zeppelin 0.8). Instead you should set spark properties (`spark.jars`, `spark.files`, `spark.jars.packages`) in 2 ways. +For spark interpreter, it is not recommended to use Zeppelin's [Dependency Management](../usage/interpreter/dependency_management.html) for managing +third party dependencies (`%spark.dep` is removed from Zeppelin 0.9 as well). Instead you should set the standard Spark properties. - - + + + + + + + - + - - - - - - +
spark-defaults.confSPARK_SUBMIT_OPTIONSSpark PropertySpark Submit Argument Description
spark.files--filesComma-separated list of files to be placed in the working directory of each executor. Globs are allowed.
spark.jars --jarsComma-separated list of local jars to include on the driver and executor classpaths.Comma-separated list of jars to include on the driver and executor classpaths. Globs are allowed.
spark.jars.packages --packagesComma-separated list of maven coordinates of jars to include on the driver and executor classpaths. Will search the local maven repo, then maven central and any additional remote repositories given by --repositories. The format for the coordinates should be groupId:artifactId:version.
spark.files--filesComma-separated list of files to be placed in the working directory of each executor.Comma-separated list of Maven coordinates of jars to include on the driver and executor classpaths. The coordinates should be groupId:artifactId:version. If spark.jars.ivySettings is given artifacts will be resolved according to the configuration in the file, otherwise artifacts will be searched for in the local maven repo, then maven central and finally any additional remote repositories given by the command-line option --repositories.
-### 1. Set spark properties in zeppelin side. +You can either set Spark properties in interpreter setting page or set Spark submit arguments in `zeppelin-env.sh` via environment variable `SPARK_SUBMIT_OPTIONS`. +For examples: + +```bash +export SPARK_SUBMIT_OPTIONS="--files --jars --packages " +``` + +But it is not recommended to set them in `SPARK_SUBMIT_OPTIONS`. Because it will be shared by all spark interpreters, which means you can not set different dependencies for different users. -In zeppelin side, you can either set them in spark interpreter setting page or via [Generic ConfInterpreter](../usage/interpreter/overview.html). -It is not recommended to set them in `SPARK_SUBMIT_OPTIONS`. Because it will be shared by all spark interpreters, you can not set different dependencies for different users. -### 2. Set spark properties in spark side. +## PySpark -In spark side, you can set them in `spark-defaults.conf`. +There're 2 ways to use PySpark in Zeppelin: -e.g. +* Vanilla PySpark +* IPySpark - ``` - spark.jars /path/mylib1.jar,/path/mylib2.jar - spark.jars.packages com.databricks:spark-csv_2.10:1.2.0 - spark.files /path/mylib1.py,/path/mylib2.egg,/path/mylib3.zip - ``` +### Vanilla PySpark (Not Recommended) +Vanilla PySpark interpreter is almost the same as vanilla Python interpreter except Zeppelin inject SparkContext, SQLContext, SparkSession via variables `sc`, `sqlContext`, `spark`. +By default, Zeppelin would use IPython in `%spark.pyspark` when IPython is available, Otherwise it would fall back to the original PySpark implementation. +If you don't want to use IPython, then you can set `zeppelin.pyspark.useIPython` as `false` in interpreter setting. For the IPython features, you can refer doc +[Python Interpreter](python.html) -## ZeppelinContext -Zeppelin automatically injects `ZeppelinContext` as variable `z` in your Scala/Python environment. `ZeppelinContext` provides some additional functions and utilities. -See [Zeppelin-Context](../usage/other_features/zeppelin_context.html) for more details. +### IPySpark (Recommended) +You can use `IPySpark` explicitly via `%spark.ipyspark`. IPySpark interpreter is almost the same as IPython interpreter except Zeppelin inject SparkContext, SQLContext, SparkSession via variables `sc`, `sqlContext`, `spark`. +For the IPython features, you can refer doc [Python Interpreter](python.html) + +## SparkR + +Zeppelin support SparkR via `%spark.r`. Here's configuration for SparkR Interpreter. + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Spark PropertyDefaultDescription
zeppelin.R.cmdRR binary executable path.
zeppelin.R.knitrtrueWhether use knitr or not. (It is recommended to install knitr and use it in Zeppelin)
zeppelin.R.image.width100%R plotting image width.
zeppelin.R.render.optionsout.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2R plotting options.
+ + +## SparkSql -## Matplotlib Integration (pyspark) -Both the `python` and `pyspark` interpreters have built-in support for inline visualization using `matplotlib`, -a popular plotting library for python. More details can be found in the [python interpreter documentation](../interpreter/python.html), -since matplotlib support is identical. More advanced interactive plotting can be done with pyspark through -utilizing Zeppelin's built-in [Angular Display System](../usage/display_system/angular_backend.html), as shown below: +Spark Sql Interpreter share the same SparkContext/SparkSession with other Spark interpreter. That means any table registered in scala, python or r code can be accessed by Spark Sql. +For examples: - +```scala +%spark + +case class People(name: String, age: Int) +var df = spark.createDataFrame(List(People("jeff", 23), People("andy", 20))) +df.createOrReplaceTempView("people") +``` + +```sql + +%spark.sql + +select * from people +``` -## Running spark sql concurrently By default, each sql statement would run sequentially in `%spark.sql`. But you can run them concurrently by following setup. -1. set `zeppelin.spark.concurrentSQL` to true to enable the sql concurrent feature, underneath zeppelin will change to use fairscheduler for spark. And also set `zeppelin.spark.concurrentSQL.max` to control the max number of sql statements running concurrently. -2. configure pools by creating `fairscheduler.xml` under your `SPARK_CONF_DIR`, check the offical spark doc [Configuring Pool Properties](http://spark.apache.org/docs/latest/job-scheduling.html#configuring-pool-properties) -3. set pool property via setting paragraph property. e.g. +1. Set `zeppelin.spark.concurrentSQL` to true to enable the sql concurrent feature, underneath zeppelin will change to use fairscheduler for spark. And also set `zeppelin.spark.concurrentSQL.max` to control the max number of sql statements running concurrently. +2. Configure pools by creating `fairscheduler.xml` under your `SPARK_CONF_DIR`, check the official spark doc [Configuring Pool Properties](http://spark.apache.org/docs/latest/job-scheduling.html#configuring-pool-properties) +3. Set pool property via setting paragraph property. e.g. ``` %spark(pool=pool1) @@ -307,19 +388,44 @@ By default, each sql statement would run sequentially in `%spark.sql`. But you c sql statement ``` -This feature is available for both all versions of scala spark, pyspark. For sparkr, it is only available starting from 2.3.0. +This pool feature is also available for all versions of scala Spark, PySpark. For SparkR, it is only available starting from 2.3.0. -## Interpreter setting option +## Interpreter Setting Option -You can choose one of `shared`, `scoped` and `isolated` options wheh you configure Spark interpreter. -Spark interpreter creates separated Scala compiler per each notebook but share a single SparkContext in `scoped` mode (experimental). -It creates separated SparkContext per each notebook in `isolated` mode. +You can choose one of `shared`, `scoped` and `isolated` options when you configure Spark interpreter. +e.g. -## IPython support +* In `scoped` per user mode, Zeppelin creates separated Scala compiler for each user but share a single SparkContext. +* In `isolated` per user mode, Zeppelin creates separated SparkContext for each user. -By default, zeppelin would use IPython in `pyspark` when IPython is available, Otherwise it would fall back to the original PySpark implementation. -If you don't want to use IPython, then you can set `zeppelin.pyspark.useIPython` as `false` in interpreter setting. For the IPython features, you can refer doc -[Python Interpreter](python.html) +## ZeppelinContext +Zeppelin automatically injects `ZeppelinContext` as variable `z` in your Scala/Python environment. `ZeppelinContext` provides some additional functions and utilities. +See [Zeppelin-Context](../usage/other_features/zeppelin_context.html) for more details. + +## User Impersonation + +In yarn mode, the user who launch the zeppelin server will be used to launch the spark yarn application. This is not a good practise. +Most of time, you will enable shiro in Zeppelin and would like to use the login user to submit the spark yarn app. For this purpose, +you need to enable user impersonation for more security control. In order the enable user impersonation, you need to do the following steps + +**Step 1** Enable user impersonation setting hadoop's `core-site.xml`. E.g. if you are using user `zeppelin` to launch Zeppelin, then add the following to `core-site.xml`, then restart both hdfs and yarn. + +``` + + hadoop.proxyuser.zeppelin.groups + * + + + hadoop.proxyuser.zeppelin.hosts + * + +``` + +**Step 2** Enable interpreter user impersonation in Spark interpreter's interpreter setting. (Enable shiro first of course) + + +**Step 3(Optional)** If you are using kerberos cluster, then you need to set `zeppelin.server.kerberos.keytab` and `zeppelin.server.kerberos.principal` to the user(aka. user in Step 1) you want to +impersonate in `zeppelin-site.xml`. ## Setting up Zeppelin with Kerberos @@ -338,10 +444,7 @@ You can get rid of this message by setting `zeppelin.spark.deprecatedMsg.show` t 1. On the server that Zeppelin is installed, install Kerberos client modules and configuration, krb5.conf. This is to make the server communicate with KDC. -2. Set `SPARK_HOME` in `[ZEPPELIN_HOME]/conf/zeppelin-env.sh` to use spark-submit -(Additionally, you might have to set `export HADOOP_CONF_DIR=/etc/hadoop/conf`) - -3. Add the two properties below to Spark configuration (`[SPARK_HOME]/conf/spark-defaults.conf`): +2. Add the two properties below to Spark configuration (`[SPARK_HOME]/conf/spark-defaults.conf`): ``` spark.yarn.principal @@ -350,5 +453,5 @@ This is to make the server communicate with KDC. > **NOTE:** If you do not have permission to access for the above spark-defaults.conf file, optionally, you can add the above lines to the Spark Interpreter setting through the Interpreter tab in the Zeppelin UI. -4. That's it. Play with Zeppelin! +3. That's it. Play with Zeppelin! diff --git a/docs/usage/interpreter/overview.md b/docs/usage/interpreter/overview.md index 3fe0f5fe105..ef2eda95750 100644 --- a/docs/usage/interpreter/overview.md +++ b/docs/usage/interpreter/overview.md @@ -132,7 +132,7 @@ Before 0.8.0, Zeppelin didn't have lifecycle management for interpreters. Users Users can change this threshold via the `zeppelin.interpreter.lifecyclemanager.timeout.threshold` setting. `TimeoutLifecycleManager` is the default lifecycle manager, and users can change it via `zeppelin.interpreter.lifecyclemanager.class`. -## Generic ConfInterpreter +## Inline Generic ConfInterpreter Zeppelin's interpreter setting is shared by all users and notes, if you want to have different settings, you have to create a new interpreter, e.g. you can create `spark_jar1` for running Spark with dependency jar1 and `spark_jar2` for running Spark with dependency jar2. This approach works, but is not particularly convenient. `ConfInterpreter` can provide more fine-grained control on interpreter settings and more flexibility. diff --git a/spark/interpreter/src/main/resources/interpreter-setting.json b/spark/interpreter/src/main/resources/interpreter-setting.json index 77392218e01..5fbccaf6cba 100644 --- a/spark/interpreter/src/main/resources/interpreter-setting.json +++ b/spark/interpreter/src/main/resources/interpreter-setting.json @@ -5,6 +5,48 @@ "className": "org.apache.zeppelin.spark.SparkInterpreter", "defaultInterpreter": true, "properties": { + "SPARK_HOME": { + "envName": "SPARK_HOME", + "propertyName": "SPARK_HOME", + "defaultValue": "", + "description": "Location of spark distribution", + "type": "string" + }, + "master": { + "envName": "", + "propertyName": "spark.master", + "defaultValue": "local[*]", + "description": "Spark master uri. ex) spark://master_host:7077", + "type": "string" + }, + "spark.app.name": { + "envName": "", + "propertyName": "spark.app.name", + "defaultValue": "Zeppelin", + "description": "The name of spark application.", + "type": "string" + }, + "spark.driver.cores": { + "envName": "", + "propertyName": "spark.driver.cores", + "defaultValue": "1", + "description": "Number of cores to use for the driver process, only in cluster mode.", + "type": "int" + }, + "spark.driver.memory": { + "envName": "", + "propertyName": "spark.driver.memory", + "defaultValue": "1g", + "description": "Amount of memory to use for the driver process, i.e. where SparkContext is initialized, in the same format as JVM memory strings with a size unit suffix (\"k\", \"m\", \"g\" or \"t\") (e.g. 512m, 2g).", + "type": "string" + }, + "spark.executor.cores": { + "envName": null, + "propertyName": "spark.executor.cores", + "defaultValue": "1", + "description": "The number of cores to use on each executor", + "type": "int" + }, "spark.executor.memory": { "envName": null, "propertyName": "spark.executor.memory", @@ -12,55 +54,50 @@ "description": "Executor memory per worker instance. ex) 512m, 32g", "type": "string" }, - "args": { + "spark.files": { "envName": null, - "propertyName": null, + "propertyName": "spark.files", "defaultValue": "", - "description": "spark commandline args", - "type": "textarea" + "description": "Comma-separated list of files to be placed in the working directory of each executor. Globs are allowed.", + "type": "string" + }, + "spark.jars": { + "envName": null, + "propertyName": "spark.jars", + "defaultValue": "", + "description": "Comma-separated list of jars to include on the driver and executor classpaths. Globs are allowed.", + "type": "string" + }, + "spark.jars.packages": { + "envName": null, + "propertyName": "spark.jars.packages", + "defaultValue": "", + "description": "Comma-separated list of Maven coordinates of jars to include on the driver and executor classpaths. The coordinates should be groupId:artifactId:version. If spark.jars.ivySettings is given artifacts will be resolved according to the configuration in the file, otherwise artifacts will be searched for in the local maven repo, then maven central and finally any additional remote repositories given by the command-line option --repositories.", + "type": "string" }, "zeppelin.spark.useHiveContext": { - "envName": "ZEPPELIN_SPARK_USEHIVECONTEXT", + "envName": null, "propertyName": "zeppelin.spark.useHiveContext", "defaultValue": true, - "description": "Use HiveContext instead of SQLContext if it is true.", + "description": "Use HiveContext instead of SQLContext if it is true. Enable hive for SparkSession.", "type": "checkbox" }, - "spark.app.name": { - "envName": "SPARK_APP_NAME", - "propertyName": "spark.app.name", - "defaultValue": "Zeppelin", - "description": "The name of spark application.", - "type": "string" - }, + "zeppelin.spark.printREPLOutput": { "envName": null, "propertyName": "zeppelin.spark.printREPLOutput", "defaultValue": true, - "description": "Print REPL output", + "description": "Print scala REPL output", "type": "checkbox" }, - "spark.cores.max": { - "envName": null, - "propertyName": "spark.cores.max", - "defaultValue": "", - "description": "Total number of cores to use. Empty value uses all available core.", - "type": "number" - }, "zeppelin.spark.maxResult": { - "envName": "ZEPPELIN_SPARK_MAXRESULT", + "envName": null, "propertyName": "zeppelin.spark.maxResult", "defaultValue": "1000", "description": "Max number of Spark SQL result to display.", "type": "number" }, - "master": { - "envName": "MASTER", - "propertyName": "spark.master", - "defaultValue": "local[*]", - "description": "Spark master uri. ex) spark://masterhost:7077", - "type": "string" - }, + "zeppelin.spark.enableSupportedVersionCheck": { "envName": null, "propertyName": "zeppelin.spark.enableSupportedVersionCheck", @@ -110,21 +147,21 @@ "className": "org.apache.zeppelin.spark.SparkSqlInterpreter", "properties": { "zeppelin.spark.concurrentSQL": { - "envName": "ZEPPELIN_SPARK_CONCURRENTSQL", + "envName": null, "propertyName": "zeppelin.spark.concurrentSQL", "defaultValue": false, "description": "Execute multiple SQL concurrently if set true.", "type": "checkbox" }, "zeppelin.spark.concurrentSQL.max": { - "envName": "ZEPPELIN_SPARK_CONCURRENTSQL_MAX", + "envName": null, "propertyName": "zeppelin.spark.concurrentSQL.max", "defaultValue": 10, "description": "Max number of SQL concurrently executed", "type": "number" }, "zeppelin.spark.sql.stacktrace": { - "envName": "ZEPPELIN_SPARK_SQL_STACKTRACE", + "envName": null, "propertyName": "zeppelin.spark.sql.stacktrace", "defaultValue": false, "description": "Show full exception stacktrace for SQL queries if set to true.", @@ -134,18 +171,18 @@ "envName": null, "propertyName": "zeppelin.spark.sql.interpolation", "defaultValue": false, - "description": "Enable ZeppelinContext variable interpolation into paragraph text", + "description": "Enable ZeppelinContext variable interpolation into spark sql", "type": "checkbox" }, "zeppelin.spark.maxResult": { - "envName": "ZEPPELIN_SPARK_MAXRESULT", + "envName": null, "propertyName": "zeppelin.spark.maxResult", "defaultValue": "1000", "description": "Max number of Spark SQL result to display.", "type": "number" }, "zeppelin.spark.importImplicit": { - "envName": "ZEPPELIN_SPARK_IMPORTIMPLICIT", + "envName": null, "propertyName": "zeppelin.spark.importImplicit", "defaultValue": true, "description": "Import implicits, UDF collection, and sql if set true. true by default.", @@ -168,21 +205,21 @@ "envName": "PYSPARK_PYTHON", "propertyName": "PYSPARK_PYTHON", "defaultValue": "python", - "description": "Python command to run pyspark with", + "description": "Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). Property spark.pyspark.driver.python take precedence if it is set", "type": "string" }, "PYSPARK_DRIVER_PYTHON": { "envName": "PYSPARK_DRIVER_PYTHON", "propertyName": "PYSPARK_DRIVER_PYTHON", "defaultValue": "python", - "description": "Python command to run pyspark with", + "description": "Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). Property spark.pyspark.driver.python take precedence if it is set", "type": "string" }, "zeppelin.pyspark.useIPython": { "envName": null, "propertyName": "zeppelin.pyspark.useIPython", "defaultValue": true, - "description": "whether use IPython when it is available", + "description": "Whether use IPython when it is available", "type": "checkbox" } }, @@ -210,28 +247,28 @@ "className": "org.apache.zeppelin.spark.SparkRInterpreter", "properties": { "zeppelin.R.knitr": { - "envName": "ZEPPELIN_R_KNITR", + "envName": null, "propertyName": "zeppelin.R.knitr", "defaultValue": true, - "description": "whether use knitr or not", + "description": "Whether use knitr or not", "type": "checkbox" }, "zeppelin.R.cmd": { - "envName": "ZEPPELIN_R_CMD", + "envName": null, "propertyName": "zeppelin.R.cmd", "defaultValue": "R", - "description": "R repl path", + "description": "R binary executable path", "type": "string" }, "zeppelin.R.image.width": { - "envName": "ZEPPELIN_R_IMAGE_WIDTH", + "envName": null, "propertyName": "zeppelin.R.image.width", "defaultValue": "100%", "description": "", "type": "number" }, "zeppelin.R.render.options": { - "envName": "ZEPPELIN_R_RENDER_OPTIONS", + "envName": null, "propertyName": "zeppelin.R.render.options", "defaultValue": "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2", "description": "", From 150c7a4907a48240df87238654ce2829f3999438 Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Tue, 7 Jan 2020 17:57:44 +0800 Subject: [PATCH 03/32] [minor] Add more logging for spark interpreter (cherry picked from commit 46322ccc902aed2397774a57efa7f9efcff793d9) --- .../spark/PySparkInterpreterTest.java | 2 - .../zeppelin/spark/SparkInterpreterTest.java | 6 --- .../zeppelin/spark/SparkRInterpreterTest.java | 1 - .../spark/BaseSparkScalaInterpreter.scala | 42 ++++++------------- .../integration/ZeppelinSparkClusterTest.java | 2 - 5 files changed, 12 insertions(+), 41 deletions(-) diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java index 2445cce9c01..7e486661406 100644 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/PySparkInterpreterTest.java @@ -54,7 +54,6 @@ public void setUp() throws InterpreterException { properties.setProperty("zeppelin.pyspark.python", "python"); properties.setProperty("zeppelin.dep.localrepo", Files.createTempDir().getAbsolutePath()); properties.setProperty("zeppelin.pyspark.useIPython", "false"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.python.gatewayserver_address", "127.0.0.1"); properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); @@ -109,7 +108,6 @@ public void testFailtoLaunchPythonProcess() throws InterpreterException { properties.setProperty("spark.pyspark.python", "invalid_python"); properties.setProperty("zeppelin.python.useIPython", "false"); properties.setProperty("zeppelin.python.gatewayserver_address", "127.0.0.1"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.maxResult", "3"); interpreter = new LazyOpenInterpreter(new PySparkInterpreter(properties)); diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java index 1feb002350c..b453b13dd09 100644 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkInterpreterTest.java @@ -72,7 +72,6 @@ public void testSparkInterpreter() throws IOException, InterruptedException, Int properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.uiWebUrl", "fake_spark_weburl"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -388,7 +387,6 @@ public void testDisableReplOutput() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.printREPLOutput", "false"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -416,7 +414,6 @@ public void testSchedulePool() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("spark.scheduler.mode", "FAIR"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -446,7 +443,6 @@ public void testDisableSparkUI_1() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("spark.ui.enabled", "false"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -472,7 +468,6 @@ public void testDisableSparkUI_2() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.spark.ui.hidden", "true"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); @@ -497,7 +492,6 @@ public void testScopedMode() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); // disable color output for easy testing properties.setProperty("zeppelin.spark.scala.color", "false"); properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java index 65843917112..011812ec95d 100644 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java @@ -54,7 +54,6 @@ public void setUp() throws InterpreterException { properties.setProperty("spark.master", "local"); properties.setProperty("spark.app.name", "test"); properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.spark.test", "true"); properties.setProperty("zeppelin.R.knitr", "true"); properties.setProperty("spark.r.backendConnectionTimeout", "10"); properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); diff --git a/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala b/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala index 87500114b68..e62fc96900f 100644 --- a/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala +++ b/spark/spark-scala-parent/src/main/scala/org/apache/zeppelin/spark/BaseSparkScalaInterpreter.scala @@ -52,8 +52,6 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, protected lazy val LOGGER: Logger = LoggerFactory.getLogger(getClass) - private val isTest = conf.getBoolean("zeppelin.spark.test", false) - protected var sc: SparkContext = _ protected var sqlContext: SQLContext = _ @@ -197,9 +195,7 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, private def spark1CreateContext(): Unit = { this.sc = SparkContext.getOrCreate(conf) - if (!isTest) { - interpreterOutput.write("Created SparkContext.\n".getBytes()) - } + LOGGER.info("Created SparkContext") getUserFiles().foreach(file => sc.addFile(file)) sc.getClass.getMethod("ui").invoke(sc).asInstanceOf[Option[_]] match { @@ -214,19 +210,13 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, if (hiveEnabled && hiveSiteExisted) { sqlContext = Class.forName("org.apache.spark.sql.hive.HiveContext") .getConstructor(classOf[SparkContext]).newInstance(sc).asInstanceOf[SQLContext] - if (!isTest) { - interpreterOutput.write("Created sql context (with Hive support).\n".getBytes()) - } + LOGGER.info("Created sql context (with Hive support)") } else { - if (hiveEnabled && !hiveSiteExisted && !isTest) { - interpreterOutput.write(("spark.useHiveContext is set as true but no hive-site.xml" + - " is found in classpath, so zeppelin will fallback to SQLContext.\n").getBytes()) - } + LOGGER.warn("spark.useHiveContext is set as true but no hive-site.xml" + + " is found in classpath, so zeppelin will fallback to SQLContext"); sqlContext = Class.forName("org.apache.spark.sql.SQLContext") .getConstructor(classOf[SparkContext]).newInstance(sc).asInstanceOf[SQLContext] - if (!isTest) { - interpreterOutput.write("Created sql context.\n".getBytes()) - } + LOGGER.info("Created sql context (without Hive support)") } bind("sc", "org.apache.spark.SparkContext", sc, List("""@transient""")) @@ -258,28 +248,20 @@ abstract class BaseSparkScalaInterpreter(val conf: SparkConf, if (hiveSiteExisted && hiveClassesPresent) { builder.getClass.getMethod("enableHiveSupport").invoke(builder) sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder) - if (!isTest) { - interpreterOutput.write("Created Spark session (with Hive support).\n".getBytes()) - } + LOGGER.info("Created Spark session (with Hive support)"); } else { - if (!hiveClassesPresent && !isTest) { - interpreterOutput.write( - "Hive support can not be enabled because spark is not built with hive\n".getBytes) + if (!hiveClassesPresent) { + LOGGER.warn("Hive support can not be enabled because spark is not built with hive") } - if (!hiveSiteExisted && !isTest) { - interpreterOutput.write( - "Hive support can not be enabled because no hive-site.xml found\n".getBytes) + if (!hiveSiteExisted) { + LOGGER.warn("Hive support can not be enabled because no hive-site.xml found") } sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder) - if (!isTest) { - interpreterOutput.write("Created Spark session.\n".getBytes()) - } + LOGGER.info("Created Spark session (without Hive support)"); } } else { sparkSession = builder.getClass.getMethod("getOrCreate").invoke(builder) - if (!isTest) { - interpreterOutput.write("Created Spark session.\n".getBytes()) - } + LOGGER.info("Created Spark session (without Hive support)"); } sc = sparkSession.getClass.getMethod("sparkContext").invoke(sparkSession) diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java index 0cb6db80e17..81e476f7f9e 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java @@ -109,8 +109,6 @@ public void setupSparkInterpreter(String sparkHome) throws InterpreterException new InterpreterProperty("zeppelin.pyspark.useIPython", "false")); sparkProperties.put("zeppelin.spark.useNew", new InterpreterProperty("zeppelin.spark.useNew", "true")); - sparkProperties.put("zeppelin.spark.test", - new InterpreterProperty("zeppelin.spark.test", "true")); sparkProperties.put("spark.serializer", new InterpreterProperty("spark.serializer", "org.apache.spark.serializer.KryoSerializer")); sparkProperties.put("zeppelin.spark.scala.color", From e2fe764dc4bfac6a153f4774618e711f41994aac Mon Sep 17 00:00:00 2001 From: Frank Oosterhuis Date: Tue, 7 Jan 2020 14:13:53 +0100 Subject: [PATCH 04/32] [ZEPPELIN-4536] Select name when creating a node ### What is this PR for? Making life a little easier when creating notes into folders, by selecting only the filename rather than the whole path. ### What type of PR is it? Improvement ### Todos ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4536 ### How should this be tested? * Test if you can create a note on the rootnode * Test if you can create a note on deeper levels ### Screenshots (if appropriate) ![image](https://user-images.githubusercontent.com/6542403/71891703-77c41680-3147-11ea-9f4c-47952fd30b4b.png) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Frank Oosterhuis Closes #3591 from frankivo/ZEPPELIN-4536 and squashes the following commits: f905d49f2 [Frank Oosterhuis] [ZEPPELIN-4536] Restore original selector 049ea0fe2 [Frank Oosterhuis] [ZEPPELIN-4536] Removed variable. 2e74ede7a [Frank Oosterhuis] Merge branch 'master' into ZEPPELIN-4536 091db5001 [Frank Oosterhuis] [ZEPPELIN-4536] Simplify startpos 47292f085 [Frank Oosterhuis] [ZEPPELIN-4536] Calc start 436c199a9 [Frank Oosterhuis] [ZEPPELIN-4536] Im getting frustrated with angular 090f7a764 [Frank Oosterhuis] [ZEPPELIN-4536] Use HTMLInputElement 6af6b9cd0 [Frank Oosterhuis] [ZEPPELIN-4536] Select name in path --- zeppelin-web/src/components/note-create/visible.directive.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zeppelin-web/src/components/note-create/visible.directive.js b/zeppelin-web/src/components/note-create/visible.directive.js index 7ba8db72f3d..2128f6ef6de 100644 --- a/zeppelin-web/src/components/note-create/visible.directive.js +++ b/zeppelin-web/src/components/note-create/visible.directive.js @@ -36,7 +36,9 @@ function modalvisible() { }); element.on('shown.bs.modal', function(e) { if (scope.targetinput) { - angular.element(e.target).find('input#' + scope.targetinput).select(); + let ele = angular.element(e.target).find('input#' + scope.targetinput); + ele[0].focus(); + ele[0].setSelectionRange(ele.val().lastIndexOf('/') + 1, ele.val().length); } postVisibleMethod(); }); From 49239bb211745ea8f0036f6fb8df84e00ae2b7e2 Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Thu, 2 Jan 2020 17:39:47 +0800 Subject: [PATCH 05/32] [ZEPPELIN-4517]. Use spark-2.4 as the default profile ### What is this PR for? Simple PR to make default profile of spark-2.4 ### What type of PR is it? [Improvement] ### Todos * [ ] - Task ### What is the Jira issue? * https://jira.apache.org/jira/browse/ZEPPELIN-4517 ### How should this be tested? * CI pass ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3586 from zjffdu/ZEPPELIN-4517 and squashes the following commits: cb8f5db63 [Jeff Zhang] [ZEPPELIN-4517]. Use spark-2.4 as the default profile --- dev/create_release.sh | 4 ++-- dev/publish_release.sh | 2 +- rlang/pom.xml | 2 +- .../java/org/apache/zeppelin/r/IRInterpreter.java | 2 +- spark/pom.xml | 8 ++++---- spark/scala-2.11/pom.xml | 2 +- spark/scala-2.12/pom.xml | 2 +- submarine/pom.xml | 11 +++++++++++ .../zeppelin/integration/SparkIntegrationTest24.java | 2 +- .../integration/ZeppelinSparkClusterTest24.java | 2 +- 10 files changed, 24 insertions(+), 13 deletions(-) diff --git a/dev/create_release.sh b/dev/create_release.sh index fdd33fb0bf0..cec81c0ecc5 100755 --- a/dev/create_release.sh +++ b/dev/create_release.sh @@ -98,8 +98,8 @@ function make_binary_release() { git_clone make_source_package -make_binary_release all "-Pspark-2.3 -Phadoop-2.6 -Pscala-${SCALA_VERSION}" -make_binary_release netinst "-Pspark-2.3 -Phadoop-2.6 -Pscala-${SCALA_VERSION} -pl zeppelin-interpreter,zeppelin-zengine,:zeppelin-display_${SCALA_VERSION},:zeppelin-spark-dependencies_${SCALA_VERSION},:zeppelin-spark_${SCALA_VERSION},zeppelin-web,zeppelin-server,zeppelin-distribution -am" +make_binary_release all "-Phadoop-2.6 -Pscala-${SCALA_VERSION}" +make_binary_release netinst "-Phadoop-2.6 -Pscala-${SCALA_VERSION} -pl zeppelin-interpreter,zeppelin-zengine,:zeppelin-display_${SCALA_VERSION},:zeppelin-spark-dependencies_${SCALA_VERSION},:zeppelin-spark_${SCALA_VERSION},zeppelin-web,zeppelin-server,zeppelin-distribution -am" # remove non release files and dirs rm -rf "${WORKING_DIR}/zeppelin" diff --git a/dev/publish_release.sh b/dev/publish_release.sh index 4745de99eb5..3519fdfa14c 100755 --- a/dev/publish_release.sh +++ b/dev/publish_release.sh @@ -46,7 +46,7 @@ if [[ $RELEASE_VERSION == *"SNAPSHOT"* ]]; then DO_SNAPSHOT="yes" fi -PUBLISH_PROFILES="-Ppublish-distr -Pspark-2.1 -Phadoop-2.6 -Pr" +PUBLISH_PROFILES="-Ppublish-distr -Phadoop-2.6 -Pr" PROJECT_OPTIONS="-pl !zeppelin-distribution" NEXUS_STAGING="https://repository.apache.org/service/local/staging" NEXUS_PROFILE="153446d1ac37c4" diff --git a/rlang/pom.xml b/rlang/pom.xml index a8021b4851e..ff6b16b934a 100644 --- a/rlang/pom.xml +++ b/rlang/pom.xml @@ -37,7 +37,7 @@ r 1.12.1 - 2.4.3 + 2.4.4 1.15.0 spark-${spark.version} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java b/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java index d9076b4f6e2..949b1b1a722 100644 --- a/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java +++ b/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java @@ -73,7 +73,7 @@ protected boolean isSparkSupported() { * @return */ protected int sparkVersion() { - return 20403; + return 20404; } /** diff --git a/spark/pom.xml b/spark/pom.xml index 32b006f0c2f..876b14e6494 100644 --- a/spark/pom.xml +++ b/spark/pom.xml @@ -198,8 +198,11 @@ spark-2.4 + + true + - 2.4.3 + 2.4.4 2.5.0 0.10.7 @@ -216,9 +219,6 @@ spark-2.2 - - true - 2.2.3 0.10.7 diff --git a/spark/scala-2.11/pom.xml b/spark/scala-2.11/pom.xml index 0fdb1590c2b..3cab22388e0 100644 --- a/spark/scala-2.11/pom.xml +++ b/spark/scala-2.11/pom.xml @@ -32,7 +32,7 @@ Zeppelin: Spark Interpreter Scala_2.11 - 2.4.3 + 2.4.4 2.11.12 2.11 ${spark.scala.version} diff --git a/spark/scala-2.12/pom.xml b/spark/scala-2.12/pom.xml index 086203bdde2..fd31af4e8ac 100644 --- a/spark/scala-2.12/pom.xml +++ b/spark/scala-2.12/pom.xml @@ -33,7 +33,7 @@ Zeppelin: Spark Interpreter Scala_2.12 - 2.4.3 + 2.4.4 2.12.8 2.12 ${spark.scala.version} diff --git a/submarine/pom.xml b/submarine/pom.xml index ea0a1626cf3..3d5de0b9c20 100644 --- a/submarine/pom.xml +++ b/submarine/pom.xml @@ -57,6 +57,17 @@ zeppelin-python 0.9.0-SNAPSHOT
+ + org.apache.zeppelin + zeppelin-jupyter-interpreter + ${project.version} + + + net.sf.py4j + py4j + + + org.apache.zeppelin zeppelin-shell diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java index 96b484ae24c..aae495105ea 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest24.java @@ -33,7 +33,7 @@ public SparkIntegrationTest24(String sparkVersion) { @Parameterized.Parameters public static List data() { return Arrays.asList(new Object[][]{ - {"2.4.3"} + {"2.4.4"} }); } diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java index 4431f942e65..a55a5043a47 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest24.java @@ -33,7 +33,7 @@ public ZeppelinSparkClusterTest24(String sparkVersion) throws Exception { @Parameterized.Parameters public static List data() { return Arrays.asList(new Object[][]{ - {"2.4.3"} + {"2.4.4"} }); } } From b2002754676670a911cdd5279ae6c8ea4a325984 Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Mon, 6 Jan 2020 19:02:43 +0800 Subject: [PATCH 06/32] [ZEPPELIN-4541]. Add api to checkpoint paragraph output between interpreter and zeppelin-server ### What is this PR for? In ZEPPELIN-4525 we add support of Shiny app in R interpreter, because when we refresh the note page, the iframe is not displayed, the root cause is that we only save note when paragraph is finished, while we launch shiny app in zeppelin, the paragraph is in RUNNING state. In this PR, we add api to checkpoint paragraph output so that user can see the output even after refresh note. ### What type of PR is it? [ Improvement ] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4541 ### How should this be tested? * CI pass ### Screenshots (if appropriate) ![shiny_app](https://user-images.githubusercontent.com/164491/71878752-6428a800-3167-11ea-92b5-f388650d19f5.gif) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3589 from zjffdu/ZEPPELIN-4541 and squashes the following commits: 38f8ba8ba [Jeff Zhang] [ZEPPELIN-4541]. Add api to checkpoint paragraph output between interpreter and zeppelin-server --- .../zeppelin/r/ShinyInterpreterTest.java | 3 + .../remote/RemoteInterpreterEventClient.java | 9 + .../interpreter/thrift/AngularObjectId.java | 2 +- .../thrift/AppOutputAppendEvent.java | 2 +- .../thrift/AppOutputUpdateEvent.java | 2 +- .../thrift/AppStatusUpdateEvent.java | 2 +- .../thrift/InterpreterCompletion.java | 2 +- .../interpreter/thrift/OutputAppendEvent.java | 2 +- .../thrift/OutputUpdateAllEvent.java | 2 +- .../interpreter/thrift/OutputUpdateEvent.java | 2 +- .../interpreter/thrift/ParagraphInfo.java | 2 +- .../interpreter/thrift/RegisterInfo.java | 2 +- .../thrift/RemoteApplicationResult.java | 2 +- .../thrift/RemoteInterpreterContext.java | 2 +- .../thrift/RemoteInterpreterEvent.java | 2 +- .../thrift/RemoteInterpreterEventService.java | 875 +++++++++++++++++- .../thrift/RemoteInterpreterEventType.java | 2 +- .../thrift/RemoteInterpreterResult.java | 2 +- .../RemoteInterpreterResultMessage.java | 2 +- .../thrift/RemoteInterpreterService.java | 2 +- .../thrift/RunParagraphsEvent.java | 2 +- .../interpreter/thrift/ServiceException.java | 2 +- .../RemoteInterpreterEventService.thrift | 2 + .../zeppelin/jupyter/JupyterKernelClient.java | 2 + .../zeppelin/socket/NotebookServer.java | 12 + .../RemoteInterpreterEventServer.java | 6 +- .../RemoteInterpreterProcessListener.java | 2 + .../org/apache/zeppelin/notebook/Note.java | 2 + .../apache/zeppelin/notebook/Paragraph.java | 29 + .../RemoteInterpreterOutputTestStream.java | 4 + .../scheduler/RemoteSchedulerTest.java | 4 + 31 files changed, 967 insertions(+), 21 deletions(-) diff --git a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java b/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java index 5939f9917f8..def64361020 100644 --- a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java +++ b/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java @@ -28,6 +28,7 @@ import org.apache.zeppelin.interpreter.InterpreterResult; import org.apache.zeppelin.interpreter.InterpreterResultMessage; import org.apache.zeppelin.interpreter.LazyOpenInterpreter; +import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -42,6 +43,7 @@ import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; public class ShinyInterpreterTest { @@ -240,6 +242,7 @@ protected InterpreterContext getInterpreterContext() { .setInterpreterOut(new InterpreterOutput(null)) .setLocalProperties(new HashMap<>()) .setInterpreterClassName(ShinyInterpreter.class.getName()) + .setIntpEventClient(mock(RemoteInterpreterEventClient.class)) .build(); return context; } diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java index 5ac1c0a8dcd..41768adaf7e 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterEventClient.java @@ -235,6 +235,15 @@ public synchronized void runParagraphs(String noteId, } } + public synchronized void checkpointOutput(String noteId, String paragraphId) { + try { + intpEventServiceClient.checkpointOutput(noteId, paragraphId); + } catch (TException e) { + LOGGER.warn("Fail to checkpointOutput of paragraph: " + + paragraphId + " of note: " + noteId, e); + } + } + public synchronized void onAppOutputAppend( String noteId, String paragraphId, int index, String appId, String output) { AppOutputAppendEvent event = diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java index fc1004a30c5..4b053d626b6 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AngularObjectId.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AngularObjectId implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AngularObjectId"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java index 723754a0bb8..2511ab94b26 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputAppendEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AppOutputAppendEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputAppendEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java index 0d72b31597c..8f4c9ca70d4 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppOutputUpdateEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AppOutputUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppOutputUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java index dfc5a530344..550efebd399 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/AppStatusUpdateEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class AppStatusUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("AppStatusUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java index 6d0c8f5c383..ddb5512ab39 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/InterpreterCompletion.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class InterpreterCompletion implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("InterpreterCompletion"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java index 1a8fc2e764a..c0757fe1d33 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputAppendEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class OutputAppendEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputAppendEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java index 0df11968994..944241e2c61 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateAllEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class OutputUpdateAllEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateAllEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java index f4ac7d9cce1..cea1774df53 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/OutputUpdateEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class OutputUpdateEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("OutputUpdateEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java index a2acfc13f36..465b8bf31f1 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ParagraphInfo.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class ParagraphInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ParagraphInfo"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java index 7f40f5a8a96..8744e2b7718 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RegisterInfo.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RegisterInfo implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RegisterInfo"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java index 2965912084f..d869dffa324 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteApplicationResult.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteApplicationResult implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteApplicationResult"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java index 724b9dbd928..ce9dff3eba8 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterContext.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterContext implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterContext"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java index 66f619977d8..2a992086f6f 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java index daea0190054..e1eb9e8eab3 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventService.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterEventService { public interface Iface { @@ -43,6 +43,8 @@ public interface Iface { public void updateAppStatus(AppStatusUpdateEvent event) throws org.apache.thrift.TException; + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId) throws org.apache.thrift.TException; + public void runParagraphs(RunParagraphsEvent event) throws org.apache.thrift.TException; public void addAngularObject(java.lang.String intpGroupId, java.lang.String json) throws org.apache.thrift.TException; @@ -79,6 +81,8 @@ public interface AsyncIface { public void updateAppStatus(AppStatusUpdateEvent event, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; + public void runParagraphs(RunParagraphsEvent event, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; public void addAngularObject(java.lang.String intpGroupId, java.lang.String json, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException; @@ -259,6 +263,27 @@ public void recv_updateAppStatus() throws org.apache.thrift.TException return; } + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId) throws org.apache.thrift.TException + { + send_checkpointOutput(noteId, paragraphId); + recv_checkpointOutput(); + } + + public void send_checkpointOutput(java.lang.String noteId, java.lang.String paragraphId) throws org.apache.thrift.TException + { + checkpointOutput_args args = new checkpointOutput_args(); + args.setNoteId(noteId); + args.setParagraphId(paragraphId); + sendBase("checkpointOutput", args); + } + + public void recv_checkpointOutput() throws org.apache.thrift.TException + { + checkpointOutput_result result = new checkpointOutput_result(); + receiveBase(result, "checkpointOutput"); + return; + } + public void runParagraphs(RunParagraphsEvent event) throws org.apache.thrift.TException { send_runParagraphs(event); @@ -704,6 +729,41 @@ public Void getResult() throws org.apache.thrift.TException { } } + public void checkpointOutput(java.lang.String noteId, java.lang.String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + checkReady(); + checkpointOutput_call method_call = new checkpointOutput_call(noteId, paragraphId, resultHandler, this, ___protocolFactory, ___transport); + this.___currentMethod = method_call; + ___manager.call(method_call); + } + + public static class checkpointOutput_call extends org.apache.thrift.async.TAsyncMethodCall { + private java.lang.String noteId; + private java.lang.String paragraphId; + public checkpointOutput_call(java.lang.String noteId, java.lang.String paragraphId, org.apache.thrift.async.AsyncMethodCallback resultHandler, org.apache.thrift.async.TAsyncClient client, org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.transport.TNonblockingTransport transport) throws org.apache.thrift.TException { + super(client, protocolFactory, transport, resultHandler, false); + this.noteId = noteId; + this.paragraphId = paragraphId; + } + + public void write_args(org.apache.thrift.protocol.TProtocol prot) throws org.apache.thrift.TException { + prot.writeMessageBegin(new org.apache.thrift.protocol.TMessage("checkpointOutput", org.apache.thrift.protocol.TMessageType.CALL, 0)); + checkpointOutput_args args = new checkpointOutput_args(); + args.setNoteId(noteId); + args.setParagraphId(paragraphId); + args.write(prot); + prot.writeMessageEnd(); + } + + public Void getResult() throws org.apache.thrift.TException { + if (getState() != org.apache.thrift.async.TAsyncMethodCall.State.RESPONSE_READ) { + throw new java.lang.IllegalStateException("Method call not finished!"); + } + org.apache.thrift.transport.TMemoryInputTransport memoryTransport = new org.apache.thrift.transport.TMemoryInputTransport(getFrameBuffer().array()); + org.apache.thrift.protocol.TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport); + return null; + } + } + public void runParagraphs(RunParagraphsEvent event, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { checkReady(); runParagraphs_call method_call = new runParagraphs_call(event, resultHandler, this, ___protocolFactory, ___transport); @@ -1036,6 +1096,7 @@ protected Processor(I iface, java.util.Map extends org.apache.thrift.ProcessFunction { + public checkpointOutput() { + super("checkpointOutput"); + } + + public checkpointOutput_args getEmptyArgsInstance() { + return new checkpointOutput_args(); + } + + protected boolean isOneway() { + return false; + } + + @Override + protected boolean rethrowUnhandledExceptions() { + return false; + } + + public checkpointOutput_result getResult(I iface, checkpointOutput_args args) throws org.apache.thrift.TException { + checkpointOutput_result result = new checkpointOutput_result(); + iface.checkpointOutput(args.noteId, args.paragraphId); + return result; + } + } + public static class runParagraphs extends org.apache.thrift.ProcessFunction { public runParagraphs() { super("runParagraphs"); @@ -1472,6 +1558,7 @@ protected AsyncProcessor(I iface, java.util.Map extends org.apache.thrift.AsyncProcessFunction { + public checkpointOutput() { + super("checkpointOutput"); + } + + public checkpointOutput_args getEmptyArgsInstance() { + return new checkpointOutput_args(); + } + + public org.apache.thrift.async.AsyncMethodCallback getResultHandler(final org.apache.thrift.server.AbstractNonblockingServer.AsyncFrameBuffer fb, final int seqid) { + final org.apache.thrift.AsyncProcessFunction fcall = this; + return new org.apache.thrift.async.AsyncMethodCallback() { + public void onComplete(Void o) { + checkpointOutput_result result = new checkpointOutput_result(); + try { + fcall.sendResponse(fb, result, org.apache.thrift.protocol.TMessageType.REPLY,seqid); + } catch (org.apache.thrift.transport.TTransportException e) { + _LOGGER.error("TTransportException writing to internal frame buffer", e); + fb.close(); + } catch (java.lang.Exception e) { + _LOGGER.error("Exception writing to internal frame buffer", e); + onError(e); + } + } + public void onError(java.lang.Exception e) { + byte msgType = org.apache.thrift.protocol.TMessageType.REPLY; + org.apache.thrift.TSerializable msg; + checkpointOutput_result result = new checkpointOutput_result(); + if (e instanceof org.apache.thrift.transport.TTransportException) { + _LOGGER.error("TTransportException inside handler", e); + fb.close(); + return; + } else if (e instanceof org.apache.thrift.TApplicationException) { + _LOGGER.error("TApplicationException inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = (org.apache.thrift.TApplicationException)e; + } else { + _LOGGER.error("Exception inside handler", e); + msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION; + msg = new org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage()); + } + try { + fcall.sendResponse(fb,msg,msgType,seqid); + } catch (java.lang.Exception ex) { + _LOGGER.error("Exception writing to internal frame buffer", ex); + fb.close(); + } + } + }; + } + + protected boolean isOneway() { + return false; + } + + public void start(I iface, checkpointOutput_args args, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException { + iface.checkpointOutput(args.noteId, args.paragraphId,resultHandler); + } + } + public static class runParagraphs extends org.apache.thrift.AsyncProcessFunction { public runParagraphs() { super("runParagraphs"); @@ -6836,6 +6983,732 @@ private static S scheme(org.apache. } } + public static class checkpointOutput_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("checkpointOutput_args"); + + private static final org.apache.thrift.protocol.TField NOTE_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("noteId", org.apache.thrift.protocol.TType.STRING, (short)1); + private static final org.apache.thrift.protocol.TField PARAGRAPH_ID_FIELD_DESC = new org.apache.thrift.protocol.TField("paragraphId", org.apache.thrift.protocol.TType.STRING, (short)2); + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new checkpointOutput_argsStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new checkpointOutput_argsTupleSchemeFactory(); + + public @org.apache.thrift.annotation.Nullable java.lang.String noteId; // required + public @org.apache.thrift.annotation.Nullable java.lang.String paragraphId; // required + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { + NOTE_ID((short)1, "noteId"), + PARAGRAPH_ID((short)2, "paragraphId"); + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + case 1: // NOTE_ID + return NOTE_ID; + case 2: // PARAGRAPH_ID + return PARAGRAPH_ID; + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + + // isset id assignments + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + tmpMap.put(_Fields.NOTE_ID, new org.apache.thrift.meta_data.FieldMetaData("noteId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + tmpMap.put(_Fields.PARAGRAPH_ID, new org.apache.thrift.meta_data.FieldMetaData("paragraphId", org.apache.thrift.TFieldRequirementType.DEFAULT, + new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING))); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(checkpointOutput_args.class, metaDataMap); + } + + public checkpointOutput_args() { + } + + public checkpointOutput_args( + java.lang.String noteId, + java.lang.String paragraphId) + { + this(); + this.noteId = noteId; + this.paragraphId = paragraphId; + } + + /** + * Performs a deep copy on other. + */ + public checkpointOutput_args(checkpointOutput_args other) { + if (other.isSetNoteId()) { + this.noteId = other.noteId; + } + if (other.isSetParagraphId()) { + this.paragraphId = other.paragraphId; + } + } + + public checkpointOutput_args deepCopy() { + return new checkpointOutput_args(this); + } + + @Override + public void clear() { + this.noteId = null; + this.paragraphId = null; + } + + @org.apache.thrift.annotation.Nullable + public java.lang.String getNoteId() { + return this.noteId; + } + + public checkpointOutput_args setNoteId(@org.apache.thrift.annotation.Nullable java.lang.String noteId) { + this.noteId = noteId; + return this; + } + + public void unsetNoteId() { + this.noteId = null; + } + + /** Returns true if field noteId is set (has been assigned a value) and false otherwise */ + public boolean isSetNoteId() { + return this.noteId != null; + } + + public void setNoteIdIsSet(boolean value) { + if (!value) { + this.noteId = null; + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.String getParagraphId() { + return this.paragraphId; + } + + public checkpointOutput_args setParagraphId(@org.apache.thrift.annotation.Nullable java.lang.String paragraphId) { + this.paragraphId = paragraphId; + return this; + } + + public void unsetParagraphId() { + this.paragraphId = null; + } + + /** Returns true if field paragraphId is set (has been assigned a value) and false otherwise */ + public boolean isSetParagraphId() { + return this.paragraphId != null; + } + + public void setParagraphIdIsSet(boolean value) { + if (!value) { + this.paragraphId = null; + } + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + case NOTE_ID: + if (value == null) { + unsetNoteId(); + } else { + setNoteId((java.lang.String)value); + } + break; + + case PARAGRAPH_ID: + if (value == null) { + unsetParagraphId(); + } else { + setParagraphId((java.lang.String)value); + } + break; + + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + case NOTE_ID: + return getNoteId(); + + case PARAGRAPH_ID: + return getParagraphId(); + + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + case NOTE_ID: + return isSetNoteId(); + case PARAGRAPH_ID: + return isSetParagraphId(); + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof checkpointOutput_args) + return this.equals((checkpointOutput_args)that); + return false; + } + + public boolean equals(checkpointOutput_args that) { + if (that == null) + return false; + if (this == that) + return true; + + boolean this_present_noteId = true && this.isSetNoteId(); + boolean that_present_noteId = true && that.isSetNoteId(); + if (this_present_noteId || that_present_noteId) { + if (!(this_present_noteId && that_present_noteId)) + return false; + if (!this.noteId.equals(that.noteId)) + return false; + } + + boolean this_present_paragraphId = true && this.isSetParagraphId(); + boolean that_present_paragraphId = true && that.isSetParagraphId(); + if (this_present_paragraphId || that_present_paragraphId) { + if (!(this_present_paragraphId && that_present_paragraphId)) + return false; + if (!this.paragraphId.equals(that.paragraphId)) + return false; + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + hashCode = hashCode * 8191 + ((isSetNoteId()) ? 131071 : 524287); + if (isSetNoteId()) + hashCode = hashCode * 8191 + noteId.hashCode(); + + hashCode = hashCode * 8191 + ((isSetParagraphId()) ? 131071 : 524287); + if (isSetParagraphId()) + hashCode = hashCode * 8191 + paragraphId.hashCode(); + + return hashCode; + } + + @Override + public int compareTo(checkpointOutput_args other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + lastComparison = java.lang.Boolean.valueOf(isSetNoteId()).compareTo(other.isSetNoteId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetNoteId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.noteId, other.noteId); + if (lastComparison != 0) { + return lastComparison; + } + } + lastComparison = java.lang.Boolean.valueOf(isSetParagraphId()).compareTo(other.isSetParagraphId()); + if (lastComparison != 0) { + return lastComparison; + } + if (isSetParagraphId()) { + lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.paragraphId, other.paragraphId); + if (lastComparison != 0) { + return lastComparison; + } + } + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("checkpointOutput_args("); + boolean first = true; + + sb.append("noteId:"); + if (this.noteId == null) { + sb.append("null"); + } else { + sb.append(this.noteId); + } + first = false; + if (!first) sb.append(", "); + sb.append("paragraphId:"); + if (this.paragraphId == null) { + sb.append("null"); + } else { + sb.append(this.paragraphId); + } + first = false; + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class checkpointOutput_argsStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_argsStandardScheme getScheme() { + return new checkpointOutput_argsStandardScheme(); + } + } + + private static class checkpointOutput_argsStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, checkpointOutput_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + case 1: // NOTE_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + case 2: // PARAGRAPH_ID + if (schemeField.type == org.apache.thrift.protocol.TType.STRING) { + struct.paragraphId = iprot.readString(); + struct.setParagraphIdIsSet(true); + } else { + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + break; + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, checkpointOutput_args struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + if (struct.noteId != null) { + oprot.writeFieldBegin(NOTE_ID_FIELD_DESC); + oprot.writeString(struct.noteId); + oprot.writeFieldEnd(); + } + if (struct.paragraphId != null) { + oprot.writeFieldBegin(PARAGRAPH_ID_FIELD_DESC); + oprot.writeString(struct.paragraphId); + oprot.writeFieldEnd(); + } + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class checkpointOutput_argsTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_argsTupleScheme getScheme() { + return new checkpointOutput_argsTupleScheme(); + } + } + + private static class checkpointOutput_argsTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet optionals = new java.util.BitSet(); + if (struct.isSetNoteId()) { + optionals.set(0); + } + if (struct.isSetParagraphId()) { + optionals.set(1); + } + oprot.writeBitSet(optionals, 2); + if (struct.isSetNoteId()) { + oprot.writeString(struct.noteId); + } + if (struct.isSetParagraphId()) { + oprot.writeString(struct.paragraphId); + } + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_args struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + java.util.BitSet incoming = iprot.readBitSet(2); + if (incoming.get(0)) { + struct.noteId = iprot.readString(); + struct.setNoteIdIsSet(true); + } + if (incoming.get(1)) { + struct.paragraphId = iprot.readString(); + struct.setParagraphIdIsSet(true); + } + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + + public static class checkpointOutput_result implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { + private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("checkpointOutput_result"); + + + private static final org.apache.thrift.scheme.SchemeFactory STANDARD_SCHEME_FACTORY = new checkpointOutput_resultStandardSchemeFactory(); + private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY = new checkpointOutput_resultTupleSchemeFactory(); + + + /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */ + public enum _Fields implements org.apache.thrift.TFieldIdEnum { +; + + private static final java.util.Map byName = new java.util.HashMap(); + + static { + for (_Fields field : java.util.EnumSet.allOf(_Fields.class)) { + byName.put(field.getFieldName(), field); + } + } + + /** + * Find the _Fields constant that matches fieldId, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByThriftId(int fieldId) { + switch(fieldId) { + default: + return null; + } + } + + /** + * Find the _Fields constant that matches fieldId, throwing an exception + * if it is not found. + */ + public static _Fields findByThriftIdOrThrow(int fieldId) { + _Fields fields = findByThriftId(fieldId); + if (fields == null) throw new java.lang.IllegalArgumentException("Field " + fieldId + " doesn't exist!"); + return fields; + } + + /** + * Find the _Fields constant that matches name, or null if its not found. + */ + @org.apache.thrift.annotation.Nullable + public static _Fields findByName(java.lang.String name) { + return byName.get(name); + } + + private final short _thriftId; + private final java.lang.String _fieldName; + + _Fields(short thriftId, java.lang.String fieldName) { + _thriftId = thriftId; + _fieldName = fieldName; + } + + public short getThriftFieldId() { + return _thriftId; + } + + public java.lang.String getFieldName() { + return _fieldName; + } + } + public static final java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap; + static { + java.util.Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new java.util.EnumMap<_Fields, org.apache.thrift.meta_data.FieldMetaData>(_Fields.class); + metaDataMap = java.util.Collections.unmodifiableMap(tmpMap); + org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(checkpointOutput_result.class, metaDataMap); + } + + public checkpointOutput_result() { + } + + /** + * Performs a deep copy on other. + */ + public checkpointOutput_result(checkpointOutput_result other) { + } + + public checkpointOutput_result deepCopy() { + return new checkpointOutput_result(this); + } + + @Override + public void clear() { + } + + public void setFieldValue(_Fields field, @org.apache.thrift.annotation.Nullable java.lang.Object value) { + switch (field) { + } + } + + @org.apache.thrift.annotation.Nullable + public java.lang.Object getFieldValue(_Fields field) { + switch (field) { + } + throw new java.lang.IllegalStateException(); + } + + /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */ + public boolean isSet(_Fields field) { + if (field == null) { + throw new java.lang.IllegalArgumentException(); + } + + switch (field) { + } + throw new java.lang.IllegalStateException(); + } + + @Override + public boolean equals(java.lang.Object that) { + if (that == null) + return false; + if (that instanceof checkpointOutput_result) + return this.equals((checkpointOutput_result)that); + return false; + } + + public boolean equals(checkpointOutput_result that) { + if (that == null) + return false; + if (this == that) + return true; + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + + return hashCode; + } + + @Override + public int compareTo(checkpointOutput_result other) { + if (!getClass().equals(other.getClass())) { + return getClass().getName().compareTo(other.getClass().getName()); + } + + int lastComparison = 0; + + return 0; + } + + @org.apache.thrift.annotation.Nullable + public _Fields fieldForId(int fieldId) { + return _Fields.findByThriftId(fieldId); + } + + public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException { + scheme(iprot).read(iprot, this); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException { + scheme(oprot).write(oprot, this); + } + + @Override + public java.lang.String toString() { + java.lang.StringBuilder sb = new java.lang.StringBuilder("checkpointOutput_result("); + boolean first = true; + + sb.append(")"); + return sb.toString(); + } + + public void validate() throws org.apache.thrift.TException { + // check for required fields + // check for sub-struct validity + } + + private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { + try { + write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, java.lang.ClassNotFoundException { + try { + read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in))); + } catch (org.apache.thrift.TException te) { + throw new java.io.IOException(te); + } + } + + private static class checkpointOutput_resultStandardSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_resultStandardScheme getScheme() { + return new checkpointOutput_resultStandardScheme(); + } + } + + private static class checkpointOutput_resultStandardScheme extends org.apache.thrift.scheme.StandardScheme { + + public void read(org.apache.thrift.protocol.TProtocol iprot, checkpointOutput_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TField schemeField; + iprot.readStructBegin(); + while (true) + { + schemeField = iprot.readFieldBegin(); + if (schemeField.type == org.apache.thrift.protocol.TType.STOP) { + break; + } + switch (schemeField.id) { + default: + org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type); + } + iprot.readFieldEnd(); + } + iprot.readStructEnd(); + + // check for required fields of primitive type, which can't be checked in the validate method + struct.validate(); + } + + public void write(org.apache.thrift.protocol.TProtocol oprot, checkpointOutput_result struct) throws org.apache.thrift.TException { + struct.validate(); + + oprot.writeStructBegin(STRUCT_DESC); + oprot.writeFieldStop(); + oprot.writeStructEnd(); + } + + } + + private static class checkpointOutput_resultTupleSchemeFactory implements org.apache.thrift.scheme.SchemeFactory { + public checkpointOutput_resultTupleScheme getScheme() { + return new checkpointOutput_resultTupleScheme(); + } + } + + private static class checkpointOutput_resultTupleScheme extends org.apache.thrift.scheme.TupleScheme { + + @Override + public void write(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol oprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + } + + @Override + public void read(org.apache.thrift.protocol.TProtocol prot, checkpointOutput_result struct) throws org.apache.thrift.TException { + org.apache.thrift.protocol.TTupleProtocol iprot = (org.apache.thrift.protocol.TTupleProtocol) prot; + } + } + + private static S scheme(org.apache.thrift.protocol.TProtocol proto) { + return (org.apache.thrift.scheme.StandardScheme.class.equals(proto.getScheme()) ? STANDARD_SCHEME_FACTORY : TUPLE_SCHEME_FACTORY).getScheme(); + } + } + public static class runParagraphs_args implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("runParagraphs_args"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java index e397607565e..06be47a1ed1 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterEventType.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public enum RemoteInterpreterEventType implements org.apache.thrift.TEnum { NO_OP(1), ANGULAR_OBJECT_ADD(2), diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java index 4f578eec968..2817903c9a8 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResult.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterResult implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResult"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java index 8cbc0546f54..e0ec93678d3 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterResultMessage.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterResultMessage implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RemoteInterpreterResultMessage"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java index f7d3cb3e831..68dc727703d 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RemoteInterpreterService.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RemoteInterpreterService { public interface Iface { diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java index 8eba9c9af06..72cae21620b 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/RunParagraphsEvent.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class RunParagraphsEvent implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("RunParagraphsEvent"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java index 039043d02d1..48861827f27 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/thrift/ServiceException.java @@ -24,7 +24,7 @@ package org.apache.zeppelin.interpreter.thrift; @SuppressWarnings({"cast", "rawtypes", "serial", "unchecked", "unused"}) -@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-06") +@javax.annotation.Generated(value = "Autogenerated by Thrift Compiler (0.13.0)", date = "2020-01-07") public class ServiceException extends org.apache.thrift.TException implements org.apache.thrift.TBase, java.io.Serializable, Cloneable, Comparable { private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("ServiceException"); diff --git a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift index 6470a67d09d..339f3e5ba41 100644 --- a/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift +++ b/zeppelin-interpreter/src/main/thrift/RemoteInterpreterEventService.thrift @@ -107,6 +107,8 @@ service RemoteInterpreterEventService { void updateAppOutput(1: AppOutputUpdateEvent event); void updateAppStatus(1: AppStatusUpdateEvent event); + void checkpointOutput(1: string noteId, 2: string paragraphId); + void runParagraphs(1: RunParagraphsEvent event); void addAngularObject(1: string intpGroupId, 2: string json); diff --git a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java index 54112d47c43..deb4afa70e3 100644 --- a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java +++ b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java @@ -119,6 +119,8 @@ private boolean checkForShinyApp(String response) throws IOException { height + "\" width=\"" + width + "\" frameBorder=\"0\">"); context.out.flush(); context.out.write("\n%text "); + context.getIntpEventClient().checkpointOutput(context.getNoteId(), + context.getParagraphId()); return true; } } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 831c76e7eb3..291d2c240bb 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -1606,6 +1606,8 @@ public void onOutputUpdated(String noteId, String paragraphId, int index, LOG.warn("Note " + noteId + " note found"); return; } + Paragraph paragraph = note.getParagraph(paragraphId); + paragraph.updateOutputBuffer(index, type, output); if (note.isPersonalizedMode()) { String user = note.getParagraph(paragraphId).getUser(); if (null != user) { @@ -1886,6 +1888,16 @@ public void onOutputUpdateAll(Paragraph paragraph, List metaInfos); List getParagraphList(String user, String noteId) throws TException, IOException; + + void checkpointOutput(String noteId, String paragraphId); } diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java index a9388a65151..dbecbf21a1c 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java @@ -641,6 +641,7 @@ public Paragraph removeParagraph(String user, String paragraphId) { public void clearParagraphOutputFields(Paragraph p) { p.setReturn(null, null); p.cleanRuntimeInfos(); + p.cleanOutputBuffer(); } public Paragraph clearPersonalizedParagraphOutput(String paragraphId, String user) { @@ -1094,6 +1095,7 @@ public static Note fromJson(String json) throws IOException { public void postProcessParagraphs() { for (Paragraph p : paragraphs) { p.cleanRuntimeInfos(); + p.cleanOutputBuffer(); p.parseText(); if (p.getStatus() == Status.PENDING || p.getStatus() == Status.RUNNING) { diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java index 5405d9e9c67..e97ea3c4e23 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Paragraph.java @@ -107,6 +107,7 @@ public class Paragraph extends JobWithProgressPoller implemen private transient Map localProperties = new HashMap<>(); // serialize runtimeInfos to frontend but not to note file (via gson's ExclusionStrategy) private Map runtimeInfos = new HashMap<>(); + private transient List outputBuffer = new ArrayList<>(); public static String PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE = "runOnSelectionChange"; private static boolean PARAGRAPH_CONFIG_RUNONSELECTIONCHANGE_DEFAULT = true; @@ -613,6 +614,7 @@ public void onUpdateAll(InterpreterOutput out) { paragraphJobListener.onOutputUpdateAll(self, messages); } updateParagraphResult(messages); + outputBuffer.clear(); } catch (IOException e) { LOGGER.error(e.getMessage(), e); } @@ -816,6 +818,22 @@ public void cleanRuntimeInfos() { this.runtimeInfos.clear(); } + public void cleanOutputBuffer() { + this.outputBuffer.clear(); + } + + /** + * Save the buffered output to InterpreterResults. So that open another tab or refresh + * note you can see the latest checkpoint's output. + */ + public void checkpointOutput() { + LOGGER.info("Checkpoint Paragraph output for paragraph: " + getId()); + this.results = new InterpreterResult(Code.SUCCESS); + for (InterpreterResultMessage buffer : outputBuffer) { + results.add(buffer); + } + } + private GUI getNoteGui() { GUI gui = new GUI(); gui.setParams(this.note.getNoteParams()); @@ -884,4 +902,15 @@ public static Paragraph fromJson(String json) { return Note.getGson().fromJson(json, Paragraph.class); } + public void updateOutputBuffer(int index, InterpreterResult.Type type, String output) { + InterpreterResultMessage interpreterResultMessage = new InterpreterResultMessage(type, output);; + if (outputBuffer.size() == index) { + outputBuffer.add(interpreterResultMessage); + } else if (outputBuffer.size() > index) { + outputBuffer.set(index, interpreterResultMessage); + } else { + LOGGER.warn("Get output of index: " + index + ", but there's only " + + outputBuffer.size() + " output in outputBuffer"); + } + } } diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java index 5a3e2258507..d232c259be8 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterOutputTestStream.java @@ -148,4 +148,8 @@ public List getParagraphList(String user, String noteId) { return null; } + @Override + public void checkpointOutput(String noteId, String paragraphId) { + + } } diff --git a/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java b/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java index acba1c85823..c768e543131 100644 --- a/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java +++ b/zeppelin-zengine/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java @@ -294,4 +294,8 @@ public List getParagraphList(String user, String noteId) { return null; } + @Override + public void checkpointOutput(String noteId, String paragraphId) { + + } } From 6af0934c6ee9706437c28431be55ab3763bb850a Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Tue, 29 Oct 2019 17:32:14 +0800 Subject: [PATCH 07/32] [ZEPPELIN-4321] Rework Zeppelin with Latest Angular ### What is this PR for? The old version of zeppelin was written with AngularJS, there exist many issues related to the zeppelin-web and could not resolve due to the low version of AngularJS. So we rework the zeppelin-web with the latest Angular (8.0). ### What type of PR is it? Feature ### Implementation progress #### Pages | Name | Route | Module | UI | | --- | ----- | ---------- | -- | | Home | `/` | HomeModule | Y | | Login | `/login` | LoginModule | Y | | Job Manager | `/jobmanager` | JobManagerModule | Y | | Interpreter Setting | `/interpreter` | InterpreterModule | Y | | Notebook | `/notebook/{id}` | NotebookModule | Y | | Notebook Repos | `/notebookRepos` | | | | Credential | `/credential` | | | | Helium | `/helium` | | WIP | | Configuration | `/configuration` | | | #### Notebook Features | Feature | Description | Status | | ------ | ---- | ---- | | Files System | Create/ Rename/ Import etc. | Y | | Toolbar Actions | The top toolbar actions | Y | #### Paragraph Features | Feature | Description | Status | | ------ | ---- | ---- | | Grid layout and resizable | | Y | | Code Editor | | Y | | Actions | The Corresponding actions of the drop-down menu in the setting button | Y | | Actions(hot-keys) | Support hot-keys for the actions | WIP | | Publishable | [publish paragraphs](http://zeppelin.apache.org/docs/0.8.0/usage/other_features/publishing_paragraphs.html) | | | Stream | | | #### Result Display | Type | Status | | ------ | ---- | | Dynamic Form | Y | | Text | Y | | Html | Y | | Table | Y | | Network | | #### Table Visualization | Type | State | | ------ | ---- | | Line Chart | Y | | Bard Chart | Y | | Pie Chart | Y | | Area Chart | Y | | Scatter Chart | Y | #### Helium Visualization | Type | Description | Status | | ------ | ---- | ---- | | Prototype | To verify the implementable prototype | Y | | Publish Dependencies | Just like [zeppelin-vis](https://github.com/apache/zeppelin/tree/master/zeppelin-web/src/app/visualization) | WIP | | Example Projects | | Y | | Development Documents | | WIP | ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4321 https://issues.apache.org/jira/browse/ZEPPELIN-4215 ### How should this be tested? #### Prerequisites - [Node.js](https://nodejs.org) version 10.9.0 or later or use [creationix/nvm](https://github.com/creationix/nvm). - NPM package manager (which is installed with Node.js by default). - [Angular CLI](https://angular.io/cli) version 8.3.0 or later. #### Install ```bash $ cd zeppelin-frontend $ npm install ``` Install dependencies in the project directory. ### Start Zeppelin server [Run Zeppelin server](https://zeppelin.apache.org/contribution/contributions.html#run-zeppelin-server-in-development-mode) on `http://localhost:8080`. If you are using a custom port instead of the default(http://localhost:8080) or other network address, you can create `.env` file in the project directory and set `SERVER_PROXY`. *.env* ``` SERVER_PROXY=http://localhost:8080 ``` ### Development server ```bash $ npm start ``` Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. ### Build Run `npm build` to build the project. The build artifacts will be stored in the `dist/` directory. ### Screenshots (if appropriate) **Login** ![login](https://user-images.githubusercontent.com/22736418/67387927-62206580-f5ca-11e9-8268-e7036f32ea1c.png) **Home** ![image](https://user-images.githubusercontent.com/22736418/67388288-f4286e00-f5ca-11e9-9265-c9290830a5cd.png) ![image](https://user-images.githubusercontent.com/22736418/67388304-f8ed2200-f5ca-11e9-9368-09b00edd1d67.png) **Interpreter** ![zp-interpreter](https://user-images.githubusercontent.com/22736418/67388335-086c6b00-f5cb-11e9-9d03-add1054c3aeb.gif) **Job Manager** ![zp-jm](https://user-images.githubusercontent.com/22736418/67388392-21751c00-f5cb-11e9-8170-f311fd0dced4.gif) **Dynamic Form** ![zp-df](https://user-images.githubusercontent.com/22736418/67388447-3ce02700-f5cb-11e9-90dd-cee932fa685c.gif) **Frontend API(latest Angular)** ![zp-ng](https://user-images.githubusercontent.com/22736418/67388538-70bb4c80-f5cb-11e9-921d-6c34a4a99711.gif) ** Visualization** ![zp-vis](https://user-images.githubusercontent.com/22736418/67388602-8c265780-f5cb-11e9-9de9-e198878bee09.gif) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? Maybe * Does this needs documentation? YES Author: Hsuan Lee Author: Wendell Author: vthinkxie Closes #3490 from hsuanxyz/frontend-next and squashes the following commits: cb673df36 [Hsuan Lee] chore: named TODOs 826b6d4c3 [Hsuan Lee] ci: add exclude item 10ea71e45 [Hsuan Lee] ci: fix ci config d48b8f9dd [Hsuan Lee] chore: rename the dirname to zeppelin-web-angular ec4475ca6 [Hsuan Lee] chore: update LICENSE and add pom.xml in zeppelin-frontend d0dc19493 [Hsuan Lee] chore: add `package-lock.json` to version control 06efeda1f [Hsuan Lee] docs: update frontend README e7f10d201 [Hsuan Lee] chore: add license header in `*.(js|md)` 564930676 [Hsuan Lee] chore: add license header 8a07902ad [Hsuan Lee] chore: update theme variables 10f7c78e0 [Hsuan Lee] chore: remove commit-lint 03ff8d58a [Hsuan Lee] fix: code editor language highlight f53ad5450 [Hsuan Lee] docs: update frontend README 95bccaf45 [Wendell] feat: add code editor 4ea8b5046 [Hsuan Lee] feat: add visualizations 3d02d0e9e [vthinkxie] chore: support basic features of zeppelin eafc5194e [Hsuan Lee] feat: add base services 27c5bdf25 [Hsuan Lee] feat: add common projects 0c39614c3 [Hsuan Lee] zeppelin-frontend init commit --- .travis.yml | 11 + LICENSE | 7 +- pom.xml | 15 +- zeppelin-web-angular/.editorconfig | 15 + zeppelin-web-angular/.gitignore | 47 + zeppelin-web-angular/.prettierignore | 3 + zeppelin-web-angular/.prettierrc | 15 + zeppelin-web-angular/README.md | 276 + zeppelin-web-angular/WEB-INF/web.xml | 41 + zeppelin-web-angular/angular.json | 330 + zeppelin-web-angular/browserslist | 12 + zeppelin-web-angular/e2e/protractor.conf.js | 44 + zeppelin-web-angular/e2e/src/app.e2e-spec.ts | 23 + zeppelin-web-angular/e2e/src/app.po.ts | 11 + zeppelin-web-angular/e2e/tsconfig.json | 13 + zeppelin-web-angular/karma.conf.js | 44 + zeppelin-web-angular/package-lock.json | 15996 ++++++++++++++++ zeppelin-web-angular/package.json | 96 + zeppelin-web-angular/pom.xml | 174 + .../projects/helium-vis-example/README.md | 36 + .../projects/helium-vis-example/karma.conf.js | 44 + .../helium-vis-example/ng-package.json | 7 + .../projects/helium-vis-example/package.json | 8 + .../src/json-vis.component.ts | 43 + .../helium-vis-example/src/json-vis.module.ts | 23 + .../src/json-visualization.ts | 64 + .../helium-vis-example/src/public-api.ts | 30 + .../projects/helium-vis-example/src/test.ts | 33 + .../helium-vis-example/tsconfig.lib.json | 26 + .../helium-vis-example/tsconfig.spec.json | 17 + .../projects/helium-vis-example/tslint.json | 17 + .../projects/zeppelin-helium/README.md | 36 + .../projects/zeppelin-helium/karma.conf.js | 44 + .../projects/zeppelin-helium/ng-package.json | 7 + .../projects/zeppelin-helium/package.json | 12 + .../zeppelin-helium/src/common-deps.ts | 43 + .../projects/zeppelin-helium/src/index.ts | 13 + .../zeppelin-helium/src/public-api.ts | 18 + .../projects/zeppelin-helium/src/test.ts | 33 + .../src/zeppelin-helium.module.ts | 16 + .../src/zeppelin-helium.service.ts | 96 + .../zeppelin-helium/tsconfig.lib.json | 27 + .../zeppelin-helium/tsconfig.spec.json | 17 + .../projects/zeppelin-helium/tslint.json | 17 + .../projects/zeppelin-sdk/README.md | 36 + .../projects/zeppelin-sdk/karma.conf.js | 44 + .../projects/zeppelin-sdk/ng-package.json | 7 + .../projects/zeppelin-sdk/package.json | 8 + .../projects/zeppelin-sdk/src/index.ts | 13 + .../zeppelin-sdk/src/interfaces/index.ts | 13 + .../interfaces/message-common.interface.ts | 129 + .../message-data-type-map.interface.ts | 164 + .../message-interpreter.interface.ts | 70 + .../src/interfaces/message-job.interface.ts | 48 + .../interfaces/message-notebook.interface.ts | 209 + .../interfaces/message-operator.interface.ts | 482 + .../interfaces/message-paragraph.interface.ts | 467 + .../zeppelin-sdk/src/interfaces/public-api.ts | 20 + .../interfaces/websocket-message.interface.ts | 21 + .../projects/zeppelin-sdk/src/message.ts | 502 + .../projects/zeppelin-sdk/src/public-api.ts | 15 + .../projects/zeppelin-sdk/tsconfig.lib.json | 27 + .../projects/zeppelin-sdk/tsconfig.spec.json | 17 + .../projects/zeppelin-sdk/tslint.json | 17 + .../projects/zeppelin-visualization/README.md | 36 + .../zeppelin-visualization/karma.conf.js | 44 + .../zeppelin-visualization/ng-package.json | 7 + .../zeppelin-visualization/package.json | 8 + .../zeppelin-visualization/src/data-set.ts | 17 + .../src/g2-visualization-base.ts | 57 + .../src/g2-visualization-component-base.ts | 93 + .../zeppelin-visualization/src/index.ts | 13 + .../src/pivot-transformation.ts | 199 + .../zeppelin-visualization/src/public-api.ts | 25 + .../zeppelin-visualization/src/table-data.ts | 35 + .../src/table-transformation.ts | 26 + .../src/transformation.ts | 46 + .../src/visualization-component-portal.ts | 46 + .../src/visualization.ts | 44 + .../zeppelin-visualization/tsconfig.lib.json | 27 + .../zeppelin-visualization/tsconfig.spec.json | 17 + .../zeppelin-visualization/tslint.json | 17 + zeppelin-web-angular/proxy.conf.js | 59 + zeppelin-web-angular/screenshot.png | Bin 0 -> 220058 bytes zeppelin-web-angular/src/.editorconfig | 12 + zeppelin-web-angular/src/.gitignore | 43 + .../src/app/app-http.interceptor.ts | 53 + .../src/app/app-message.interceptor.ts | 68 + .../src/app/app-routing.module.ts | 36 + .../src/app/app-runtime-compiler.providers.ts | 41 + .../src/app/app.component.html | 15 + .../src/app/app.component.less | 26 + .../src/app/app.component.spec.ts | 30 + zeppelin-web-angular/src/app/app.component.ts | 39 + zeppelin-web-angular/src/app/app.module.ts | 88 + .../core/copy-text/copy-text-to-clipboard.ts | 65 + .../src/app/core/copy-text/index.ts | 13 + .../src/app/core/copy-text/public-api.ts | 13 + .../destroy-hook/destroy-hook.component.ts | 23 + .../src/app/core/destroy-hook/index.ts | 13 + .../src/app/core/destroy-hook/public-api.ts | 13 + zeppelin-web-angular/src/app/core/index.ts | 13 + .../src/app/core/message-listener/index.ts | 13 + .../core/message-listener/message-listener.ts | 59 + .../app/core/message-listener/public-api.ts | 13 + .../src/app/core/public-api.ts | 15 + .../helium-manager/helium-manager.module.ts | 27 + .../helium-manager/helium-manager.service.ts | 75 + .../src/app/helium-manager/index.ts | 13 + .../src/app/helium-manager/public-api.ts | 14 + .../src/app/interfaces/index.ts | 13 + .../src/app/interfaces/interpreter.ts | 104 + .../src/app/interfaces/message-interceptor.ts | 20 + .../src/app/interfaces/node-list.ts | 41 + .../src/app/interfaces/public-api.ts | 17 + .../src/app/interfaces/security.ts | 23 + .../src/app/interfaces/ticket.ts | 29 + .../src/app/interfaces/trash-folder-id.ts | 15 + .../src/app/languages/index.ts | 13 + .../src/app/languages/load.ts | 20 + .../src/app/languages/public-api.ts | 14 + .../src/app/languages/scala.ts | 236 + .../app/pages/login/login-routing.module.ts | 29 + .../src/app/pages/login/login.component.html | 46 + .../src/app/pages/login/login.component.less | 69 + .../src/app/pages/login/login.component.ts | 47 + .../src/app/pages/login/login.module.ts | 26 + .../workspace/home/home-routing.module.ts | 29 + .../pages/workspace/home/home.component.html | 41 + .../pages/workspace/home/home.component.less | 37 + .../pages/workspace/home/home.component.ts | 48 + .../app/pages/workspace/home/home.module.ts | 27 + .../create-repository-modal.component.html | 158 + .../create-repository-modal.component.less | 19 + .../create-repository-modal.component.ts | 78 + .../interpreter/interpreter-routing.module.ts | 29 + .../interpreter/interpreter.component.html | 66 + .../interpreter/interpreter.component.less | 51 + .../interpreter/interpreter.component.ts | 186 + .../interpreter/interpreter.module.ts | 73 + .../interpreter/item/item.component.html | 447 + .../interpreter/item/item.component.less | 105 + .../interpreter/item/item.component.ts | 405 + .../job-manager/job-manager-routing.module.ts | 29 + .../job-manager/job-manager.component.html | 75 + .../job-manager/job-manager.component.less | 50 + .../job-manager/job-manager.component.ts | 138 + .../job-manager/job-manager.module.ts | 73 + .../job-status/job-status.component.html | 17 + .../job-status/job-status.component.less | 23 + .../job-status/job-status.component.ts | 37 + .../job-manager/job/job.component.html | 58 + .../job-manager/job/job.component.less | 70 + .../job-manager/job/job.component.ts | 83 + .../action-bar/action-bar.component.html | 239 + .../action-bar/action-bar.component.less | 105 + .../action-bar/action-bar.component.ts | 293 + .../add-paragraph.component.html | 17 + .../add-paragraph.component.less | 50 + .../add-paragraph/add-paragraph.component.ts | 34 + .../interpreter-binding.component.html | 55 + .../interpreter-binding.component.less | 30 + .../interpreter-binding.component.ts | 81 + .../notebook/notebook-routing.module.ts | 37 + .../notebook/notebook.component.html | 54 + .../notebook/notebook.component.less | 36 + .../workspace/notebook/notebook.component.ts | 315 + .../workspace/notebook/notebook.module.ts | 106 + .../code-editor/code-editor.component.html | 16 + .../code-editor/code-editor.component.less | 31 + .../code-editor/code-editor.component.ts | 238 + .../paragraph/control/control.component.html | 85 + .../paragraph/control/control.component.less | 73 + .../paragraph/control/control.component.ts | 304 + .../dynamic-forms.component.html | 51 + .../dynamic-forms.component.less | 24 + .../dynamic-forms/dynamic-forms.component.ts | 120 + .../paragraph/footer/footer.component.html | 16 + .../paragraph/footer/footer.component.less | 21 + .../paragraph/footer/footer.component.ts | 74 + .../paragraph/paragraph.component.html | 99 + .../paragraph/paragraph.component.less | 72 + .../notebook/paragraph/paragraph.component.ts | 653 + .../progress/progress.component.html | 16 + .../progress/progress.component.less | 12 + .../paragraph/progress/progress.component.ts | 32 + .../paragraph/result/result.component.html | 74 + .../paragraph/result/result.component.less | 78 + .../paragraph/result/result.component.ts | 360 + .../permissions/permissions.component.html | 88 + .../permissions/permissions.component.less | 33 + .../permissions/permissions.component.ts | 135 + .../revisions-comparator.component.html | 20 + .../revisions-comparator.component.less | 12 + .../revisions-comparator.component.ts | 25 + .../elastic-input.component.html | 23 + .../elastic-input.component.less | 56 + .../elastic-input/elastic-input.component.ts | 88 + .../workspace/notebook/share/share.module.ts | 26 + .../workspace/workspace-routing.module.ts | 51 + .../pages/workspace/workspace.component.html | 17 + .../pages/workspace/workspace.component.less | 26 + .../pages/workspace/workspace.component.ts | 48 + .../app/pages/workspace/workspace.guard.ts | 36 + .../app/pages/workspace/workspace.module.ts | 37 + .../app/services/array-ordering.service.ts | 62 + .../src/app/services/base-rest.ts | 45 + .../src/app/services/base-url.service.ts | 46 + .../src/app/services/completion.service.ts | 97 + .../src/app/services/helium.service.ts | 24 + .../src/app/services/index.ts | 13 + .../src/app/services/interpreter.service.ts | 84 + .../src/app/services/job-manager.service.ts | 34 + .../src/app/services/message.service.ts | 331 + .../src/app/services/ng-z.service.ts | 85 + .../src/app/services/note-action.service.ts | 72 + .../src/app/services/note-list.service.ts | 97 + .../src/app/services/note-status.service.ts | 65 + .../app/services/note-var-share.service.ts | 38 + .../src/app/services/public-api.ts | 28 + .../app/services/runtime-compiler.service.ts | 74 + .../src/app/services/save-as.service.ts | 37 + .../src/app/services/security.service.ts | 40 + .../src/app/services/ticket.service.ts | 116 + .../about-zeppelin.component.html | 28 + .../about-zeppelin.component.less | 38 + .../about-zeppelin.component.ts | 26 + .../code-editor/code-editor.component.html | 19 + .../code-editor/code-editor.component.ts | 244 + .../share/code-editor/code-editor.module.ts | 26 + .../share/code-editor/code-editor.service.ts | 104 + .../src/app/share/code-editor/index.ts | 13 + .../code-editor/nz-code-editor.definitions.ts | 46 + .../src/app/share/code-editor/public-api.ts | 16 + .../folder-rename.component.html | 32 + .../folder-rename.component.less | 12 + .../folder-rename/folder-rename.component.ts | 80 + .../app/share/header/header.component.html | 77 + .../app/share/header/header.component.less | 110 + .../src/app/share/header/header.component.ts | 86 + zeppelin-web-angular/src/app/share/index.ts | 13 + .../app/share/math-jax/math-jax.directive.ts | 24 + .../share/node-list/node-list.component.html | 139 + .../share/node-list/node-list.component.less | 82 + .../share/node-list/node-list.component.ts | 117 + .../note-create/note-create.component.html | 44 + .../note-create/note-create.component.less | 12 + .../note-create/note-create.component.ts | 105 + .../note-import/note-import.component.html | 50 + .../note-import/note-import.component.less | 19 + .../note-import/note-import.component.ts | 110 + .../note-rename/note-rename.component.html | 23 + .../note-rename/note-rename.component.less | 12 + .../note-rename/note-rename.component.ts | 37 + .../page-header/page-header.component.html | 18 + .../page-header/page-header.component.less | 17 + .../page-header/page-header.component.ts | 31 + .../app/share/pipes/humanize-bytes.pipe.ts | 40 + .../src/app/share/pipes/index.ts | 13 + .../src/app/share/pipes/public-api.ts | 13 + .../src/app/share/public-api.ts | 15 + .../src/app/share/resize-handle/index.ts | 13 + .../src/app/share/resize-handle/public-api.ts | 13 + .../resize-handle.component.html | 23 + .../resize-handle.component.less | 23 + .../resize-handle/resize-handle.component.ts | 26 + .../run-scripts/run-scripts.directive.ts | 80 + .../src/app/share/share.module.ts | 100 + .../src/app/share/spin/spin.component.html | 21 + .../src/app/share/spin/spin.component.less | 12 + .../src/app/share/spin/spin.component.ts | 26 + .../src/app/spell/spell-result.ts | 27 + .../area-chart-visualization.component.html | 35 + .../area-chart-visualization.component.less | 15 + .../area-chart-visualization.component.ts | 102 + .../area-chart/area-chart-visualization.ts | 32 + .../bar-chart-visualization.component.html | 34 + .../bar-chart-visualization.component.less | 25 + .../bar-chart-visualization.component.ts | 107 + .../bar-chart/bar-chart-visualization.ts | 31 + .../pivot-setting.component.html | 85 + .../pivot-setting.component.less | 27 + .../pivot-setting/pivot-setting.component.ts | 89 + .../scatter-setting.component.html | 98 + .../scatter-setting.component.less | 27 + .../scatter-setting.component.ts | 102 + .../common/util/calc-tick-count.ts | 22 + .../visualizations/common/util/set-x-axis.ts | 46 + .../x-axis-setting.component.html | 38 + .../x-axis-setting.component.less | 18 + .../x-axis-setting.component.ts | 78 + .../line-chart-visualization.component.html | 44 + .../line-chart-visualization.component.less | 25 + .../line-chart-visualization.component.ts | 137 + .../line-chart/line-chart-visualization.ts | 32 + .../pie-chart-visualization.component.html | 19 + .../pie-chart-visualization.component.less | 12 + .../pie-chart-visualization.component.ts | 73 + .../pie-chart/pie-chart-visualization.ts | 32 + ...scatter-chart-visualization.component.html | 19 + ...scatter-chart-visualization.component.less | 12 + .../scatter-chart-visualization.component.ts | 89 + .../scatter-chart-visualization.ts | 32 + .../table/table-visualization.component.html | 123 + .../table/table-visualization.component.less | 44 + .../table/table-visualization.component.ts | 174 + .../table/table-visualization.ts | 60 + .../visualizations/visualization.module.ts | 79 + zeppelin-web-angular/src/assets/.gitkeep | 0 .../src/assets/fonts/patua-one.woff2 | Bin 0 -> 12844 bytes .../helium-packages/helium-vis-example.umd.js | 589 + zeppelin-web-angular/src/assets/images/bg.jpg | Bin 0 -> 185723 bytes .../src/assets/images/zeppelin.png | Bin 0 -> 3810 bytes .../src/assets/images/zeppelin_svg_logo.svg | 77 + .../assets/images/zeppelin_svg_logo_bg.svg | 77 + zeppelin-web-angular/src/browserslist | 11 + .../src/environments/environment.prod.ts | 15 + .../src/environments/environment.ts | 28 + zeppelin-web-angular/src/favicon.ico | Bin 0 -> 4286 bytes zeppelin-web-angular/src/index.html | 50 + zeppelin-web-angular/src/karma.conf.js | 43 + zeppelin-web-angular/src/main.ts | 25 + zeppelin-web-angular/src/polyfills.ts | 94 + zeppelin-web-angular/src/styles.less | 19 + zeppelin-web-angular/src/styles/base.less | 18 + zeppelin-web-angular/src/styles/font.less | 20 + zeppelin-web-angular/src/styles/global.less | 124 + zeppelin-web-angular/src/styles/rewrite.less | 25 + zeppelin-web-angular/src/styles/spin.less | 150 + .../src/styles/theme/dark/antd-dark.less | 17 + .../src/styles/theme/dark/theme-dark.less | 659 + .../src/styles/theme/light/antd-light.less | 15 + .../src/styles/theme/light/theme-light.less | 659 + .../src/styles/theme/markdown.less | 166 + .../src/styles/theme/theme-mixin.less | 24 + zeppelin-web-angular/src/test.ts | 28 + zeppelin-web-angular/src/tsconfig.app.json | 8 + zeppelin-web-angular/src/tsconfig.spec.json | 9 + zeppelin-web-angular/src/tslint.json | 7 + zeppelin-web-angular/tsconfig.app.json | 18 + zeppelin-web-angular/tsconfig.json | 47 + zeppelin-web-angular/tsconfig.spec.json | 18 + zeppelin-web-angular/tslint.json | 141 + zeppelin-web-angular/webpack.partial.js | 27 + 344 files changed, 38558 insertions(+), 4 deletions(-) create mode 100644 zeppelin-web-angular/.editorconfig create mode 100644 zeppelin-web-angular/.gitignore create mode 100644 zeppelin-web-angular/.prettierignore create mode 100644 zeppelin-web-angular/.prettierrc create mode 100644 zeppelin-web-angular/README.md create mode 100644 zeppelin-web-angular/WEB-INF/web.xml create mode 100644 zeppelin-web-angular/angular.json create mode 100644 zeppelin-web-angular/browserslist create mode 100644 zeppelin-web-angular/e2e/protractor.conf.js create mode 100644 zeppelin-web-angular/e2e/src/app.e2e-spec.ts create mode 100644 zeppelin-web-angular/e2e/src/app.po.ts create mode 100644 zeppelin-web-angular/e2e/tsconfig.json create mode 100644 zeppelin-web-angular/karma.conf.js create mode 100644 zeppelin-web-angular/package-lock.json create mode 100644 zeppelin-web-angular/package.json create mode 100644 zeppelin-web-angular/pom.xml create mode 100644 zeppelin-web-angular/projects/helium-vis-example/README.md create mode 100644 zeppelin-web-angular/projects/helium-vis-example/karma.conf.js create mode 100644 zeppelin-web-angular/projects/helium-vis-example/ng-package.json create mode 100644 zeppelin-web-angular/projects/helium-vis-example/package.json create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts create mode 100644 zeppelin-web-angular/projects/helium-vis-example/src/test.ts create mode 100644 zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json create mode 100644 zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json create mode 100644 zeppelin-web-angular/projects/helium-vis-example/tslint.json create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/README.md create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/ng-package.json create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/package.json create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/test.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json create mode 100644 zeppelin-web-angular/projects/zeppelin-helium/tslint.json create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/README.md create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/package.json create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json create mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/tslint.json create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/README.md create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/package.json create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json create mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/tslint.json create mode 100644 zeppelin-web-angular/proxy.conf.js create mode 100644 zeppelin-web-angular/screenshot.png create mode 100644 zeppelin-web-angular/src/.editorconfig create mode 100644 zeppelin-web-angular/src/.gitignore create mode 100644 zeppelin-web-angular/src/app/app-http.interceptor.ts create mode 100644 zeppelin-web-angular/src/app/app-message.interceptor.ts create mode 100644 zeppelin-web-angular/src/app/app-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts create mode 100644 zeppelin-web-angular/src/app/app.component.html create mode 100644 zeppelin-web-angular/src/app/app.component.less create mode 100644 zeppelin-web-angular/src/app/app.component.spec.ts create mode 100644 zeppelin-web-angular/src/app/app.component.ts create mode 100644 zeppelin-web-angular/src/app/app.module.ts create mode 100644 zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts create mode 100644 zeppelin-web-angular/src/app/core/copy-text/index.ts create mode 100644 zeppelin-web-angular/src/app/core/copy-text/public-api.ts create mode 100644 zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts create mode 100644 zeppelin-web-angular/src/app/core/destroy-hook/index.ts create mode 100644 zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts create mode 100644 zeppelin-web-angular/src/app/core/index.ts create mode 100644 zeppelin-web-angular/src/app/core/message-listener/index.ts create mode 100644 zeppelin-web-angular/src/app/core/message-listener/message-listener.ts create mode 100644 zeppelin-web-angular/src/app/core/message-listener/public-api.ts create mode 100644 zeppelin-web-angular/src/app/core/public-api.ts create mode 100644 zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts create mode 100644 zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts create mode 100644 zeppelin-web-angular/src/app/helium-manager/index.ts create mode 100644 zeppelin-web-angular/src/app/helium-manager/public-api.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/index.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/interpreter.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/message-interceptor.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/node-list.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/public-api.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/security.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/ticket.ts create mode 100644 zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts create mode 100644 zeppelin-web-angular/src/app/languages/index.ts create mode 100644 zeppelin-web-angular/src/app/languages/load.ts create mode 100644 zeppelin-web-angular/src/app/languages/public-api.ts create mode 100644 zeppelin-web-angular/src/app/languages/scala.ts create mode 100644 zeppelin-web-angular/src/app/pages/login/login-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/login/login.component.html create mode 100644 zeppelin-web-angular/src/app/pages/login/login.component.less create mode 100644 zeppelin-web-angular/src/app/pages/login/login.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/login/login.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts create mode 100644 zeppelin-web-angular/src/app/services/array-ordering.service.ts create mode 100644 zeppelin-web-angular/src/app/services/base-rest.ts create mode 100644 zeppelin-web-angular/src/app/services/base-url.service.ts create mode 100644 zeppelin-web-angular/src/app/services/completion.service.ts create mode 100644 zeppelin-web-angular/src/app/services/helium.service.ts create mode 100644 zeppelin-web-angular/src/app/services/index.ts create mode 100644 zeppelin-web-angular/src/app/services/interpreter.service.ts create mode 100644 zeppelin-web-angular/src/app/services/job-manager.service.ts create mode 100644 zeppelin-web-angular/src/app/services/message.service.ts create mode 100644 zeppelin-web-angular/src/app/services/ng-z.service.ts create mode 100644 zeppelin-web-angular/src/app/services/note-action.service.ts create mode 100644 zeppelin-web-angular/src/app/services/note-list.service.ts create mode 100644 zeppelin-web-angular/src/app/services/note-status.service.ts create mode 100644 zeppelin-web-angular/src/app/services/note-var-share.service.ts create mode 100644 zeppelin-web-angular/src/app/services/public-api.ts create mode 100644 zeppelin-web-angular/src/app/services/runtime-compiler.service.ts create mode 100644 zeppelin-web-angular/src/app/services/save-as.service.ts create mode 100644 zeppelin-web-angular/src/app/services/security.service.ts create mode 100644 zeppelin-web-angular/src/app/services/ticket.service.ts create mode 100644 zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html create mode 100644 zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less create mode 100644 zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts create mode 100644 zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts create mode 100644 zeppelin-web-angular/src/app/share/code-editor/index.ts create mode 100644 zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts create mode 100644 zeppelin-web-angular/src/app/share/code-editor/public-api.ts create mode 100644 zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html create mode 100644 zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less create mode 100644 zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts create mode 100644 zeppelin-web-angular/src/app/share/header/header.component.html create mode 100644 zeppelin-web-angular/src/app/share/header/header.component.less create mode 100644 zeppelin-web-angular/src/app/share/header/header.component.ts create mode 100644 zeppelin-web-angular/src/app/share/index.ts create mode 100644 zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts create mode 100644 zeppelin-web-angular/src/app/share/node-list/node-list.component.html create mode 100644 zeppelin-web-angular/src/app/share/node-list/node-list.component.less create mode 100644 zeppelin-web-angular/src/app/share/node-list/node-list.component.ts create mode 100644 zeppelin-web-angular/src/app/share/note-create/note-create.component.html create mode 100644 zeppelin-web-angular/src/app/share/note-create/note-create.component.less create mode 100644 zeppelin-web-angular/src/app/share/note-create/note-create.component.ts create mode 100644 zeppelin-web-angular/src/app/share/note-import/note-import.component.html create mode 100644 zeppelin-web-angular/src/app/share/note-import/note-import.component.less create mode 100644 zeppelin-web-angular/src/app/share/note-import/note-import.component.ts create mode 100644 zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html create mode 100644 zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less create mode 100644 zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts create mode 100644 zeppelin-web-angular/src/app/share/page-header/page-header.component.html create mode 100644 zeppelin-web-angular/src/app/share/page-header/page-header.component.less create mode 100644 zeppelin-web-angular/src/app/share/page-header/page-header.component.ts create mode 100644 zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts create mode 100644 zeppelin-web-angular/src/app/share/pipes/index.ts create mode 100644 zeppelin-web-angular/src/app/share/pipes/public-api.ts create mode 100644 zeppelin-web-angular/src/app/share/public-api.ts create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/index.ts create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/public-api.ts create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less create mode 100644 zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts create mode 100644 zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts create mode 100644 zeppelin-web-angular/src/app/share/share.module.ts create mode 100644 zeppelin-web-angular/src/app/share/spin/spin.component.html create mode 100644 zeppelin-web-angular/src/app/share/spin/spin.component.less create mode 100644 zeppelin-web-angular/src/app/share/spin/spin.component.ts create mode 100644 zeppelin-web-angular/src/app/spell/spell-result.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/visualization.module.ts create mode 100644 zeppelin-web-angular/src/assets/.gitkeep create mode 100644 zeppelin-web-angular/src/assets/fonts/patua-one.woff2 create mode 100644 zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js create mode 100644 zeppelin-web-angular/src/assets/images/bg.jpg create mode 100644 zeppelin-web-angular/src/assets/images/zeppelin.png create mode 100644 zeppelin-web-angular/src/assets/images/zeppelin_svg_logo.svg create mode 100644 zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg create mode 100644 zeppelin-web-angular/src/browserslist create mode 100644 zeppelin-web-angular/src/environments/environment.prod.ts create mode 100644 zeppelin-web-angular/src/environments/environment.ts create mode 100644 zeppelin-web-angular/src/favicon.ico create mode 100644 zeppelin-web-angular/src/index.html create mode 100644 zeppelin-web-angular/src/karma.conf.js create mode 100644 zeppelin-web-angular/src/main.ts create mode 100644 zeppelin-web-angular/src/polyfills.ts create mode 100644 zeppelin-web-angular/src/styles.less create mode 100644 zeppelin-web-angular/src/styles/base.less create mode 100644 zeppelin-web-angular/src/styles/font.less create mode 100644 zeppelin-web-angular/src/styles/global.less create mode 100644 zeppelin-web-angular/src/styles/rewrite.less create mode 100644 zeppelin-web-angular/src/styles/spin.less create mode 100644 zeppelin-web-angular/src/styles/theme/dark/antd-dark.less create mode 100644 zeppelin-web-angular/src/styles/theme/dark/theme-dark.less create mode 100644 zeppelin-web-angular/src/styles/theme/light/antd-light.less create mode 100644 zeppelin-web-angular/src/styles/theme/light/theme-light.less create mode 100644 zeppelin-web-angular/src/styles/theme/markdown.less create mode 100644 zeppelin-web-angular/src/styles/theme/theme-mixin.less create mode 100644 zeppelin-web-angular/src/test.ts create mode 100644 zeppelin-web-angular/src/tsconfig.app.json create mode 100644 zeppelin-web-angular/src/tsconfig.spec.json create mode 100644 zeppelin-web-angular/src/tslint.json create mode 100644 zeppelin-web-angular/tsconfig.app.json create mode 100644 zeppelin-web-angular/tsconfig.json create mode 100644 zeppelin-web-angular/tsconfig.spec.json create mode 100644 zeppelin-web-angular/tslint.json create mode 100644 zeppelin-web-angular/webpack.partial.js diff --git a/.travis.yml b/.travis.yml index d2979a48d40..aee4ecefeb1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -79,6 +79,17 @@ matrix: packages: - google-chrome-stable + # Run tests (in zeppelin-web-angular) + - os: linux + sudo: false + dist: xenial + jdk: "openjdk8" + env: CI="true" BUILD_FLAG="clean -DskipTests -DskipRat" TEST_FLAG="package -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_MODULES="-pl zeppelin-web-angular" + addons: + apt: + packages: + - google-chrome-stable + # Test core modules # Several tests were excluded from this configuration due to the following issues: # HeliumApplicationFactoryTest - https://issues.apache.org/jira/browse/ZEPPELIN-2470 diff --git a/LICENSE b/LICENSE index add447eff74..2edb8a83245 100644 --- a/LICENSE +++ b/LICENSE @@ -236,16 +236,19 @@ The text of each license is also included at licenses/LICENSE-[project]-[version (The MIT License) jekyll-bootstrap 0.3.0 (https://github.com/plusjade/jekyll-bootstrap) - https://github.com/plusjade/jekyll-bootstrap (The MIT License) jekyll 1.3.0 (http://jekyllrb.com/) - https://github.com/jekyll/jekyll/blob/v1.3.0/LICENSE (The MIT License) ngInfiniteScroll 1.3.4 (https://github.com/sroze/ngInfiniteScroll) - https://github.com/sroze/ngInfiniteScroll/blob/master/LICENSE + (The MIT License) @antv/G2 3.5 (https://github.com/antvis/g2) - https://github.com/antvis/g2/blob/master/LICENSE + (The MIT License) Lodash (https://lodash.com) - https://github.com/lodash/lodash/blob/master/LICENSE + (The MIT License) Monaco Editor (https://github.com/microsoft/monaco-editor) - https://github.com/microsoft/monaco-editor/blob/master/LICENSE.md ======================================================================== MIT-style licenses ======================================================================== The following components are provided under the MIT-style license. See project link for details. The text of each license is also included at licenses/LICENSE-[project]-[version].txt. - + (MIT Style) jekyll-table-of-contents (https://github.com/ghiculescu/jekyll-table-of-contents) - https://github.com/ghiculescu/jekyll-table-of-contents/blob/master/LICENSE.txt (MIT Style) lunr.js (https://github.com/olivernn/lunr.js) - https://github.com/olivernn/lunr.js/blob/v0.7.1/LICENSE - + ======================================================================== Apache licenses ======================================================================== diff --git a/pom.xml b/pom.xml index 7ef1665eabe..bfac15eaae1 100644 --- a/pom.xml +++ b/pom.xml @@ -96,6 +96,7 @@ zeppelin-jupyter zeppelin-plugins zeppelin-distribution + zeppelin-web-angular @@ -109,8 +110,8 @@ 1.12.5 - v8.9.3 - 5.5.1 + v12.3.1 + 6.9.0 1.6 @@ -1032,6 +1033,16 @@ **/e2e/**/**.spec.js package-lock.json + + **/*.json + **/browserslist + **/.prettierrc + **/.prettierignore + **/.editorconfig + **/src/**/*.svg + **/.gitkeep + + **/src/main/java/org/apache/zeppelin/jdbc/SqlCompleter.java diff --git a/zeppelin-web-angular/.editorconfig b/zeppelin-web-angular/.editorconfig new file mode 100644 index 00000000000..c220b3125b7 --- /dev/null +++ b/zeppelin-web-angular/.editorconfig @@ -0,0 +1,15 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset=utf-8 +end_of_line=lf +trim_trailing_whitespace=true +insert_final_newline=false +indent_style=space +indent_size=2 + + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/zeppelin-web-angular/.gitignore b/zeppelin-web-angular/.gitignore new file mode 100644 index 00000000000..22b094f61f7 --- /dev/null +++ b/zeppelin-web-angular/.gitignore @@ -0,0 +1,47 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events.json +speed-measure-plugin.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db + +# +.env +yarn.lock \ No newline at end of file diff --git a/zeppelin-web-angular/.prettierignore b/zeppelin-web-angular/.prettierignore new file mode 100644 index 00000000000..b9f1979fbdf --- /dev/null +++ b/zeppelin-web-angular/.prettierignore @@ -0,0 +1,3 @@ +**/*.md +**/*.less +**/*.svg diff --git a/zeppelin-web-angular/.prettierrc b/zeppelin-web-angular/.prettierrc new file mode 100644 index 00000000000..4b9bb8a441b --- /dev/null +++ b/zeppelin-web-angular/.prettierrc @@ -0,0 +1,15 @@ +{ + "singleQuote": true, + "printWidth": 120, + "tabWidth": 2, + "useTabs": false, + "htmlWhitespaceSensitivity": "ignore", + "overrides": [ + { + "files": ".prettierrc", + "options": { + "parser": "json" + } + } + ] +} diff --git a/zeppelin-web-angular/README.md b/zeppelin-web-angular/README.md new file mode 100644 index 00000000000..dea1a0d7d71 --- /dev/null +++ b/zeppelin-web-angular/README.md @@ -0,0 +1,276 @@ + + +# Zeppelin WEB + +Zeppelin notebooks front-end built with Angular. + +- Jira issue [ZEPPELIN-4321](https://issues.apache.org/jira/browse/ZEPPELIN-4321) +- Design Document: [Zeppelin Notebook Rework Proposal](https://docs.google.com/document/d/1z_VscS81Xwx_3QaexKB2s0uEMEuWKsPXh9mWFRq0-hY) + +![screenshot](/screenshot.png?raw=true "Screenshot") + +## Setup + +### Prerequisites + +- [Node.js](https://nodejs.org) version 10.9.0 or later or use [creationix/nvm](https://github.com/creationix/nvm). +- NPM package manager (which is installed with Node.js by default). +- [Angular CLI](https://angular.io/cli) version 8.3.0 or later. + +### Install + +Run the `npm install` command to install dependencies in the project directory. + +### Start Zeppelin server + +[Run Zeppelin server](https://zeppelin.apache.org/contribution/contributions.html#run-zeppelin-server-in-development-mode) on `http://localhost:8080`. + +If you are using a custom port instead of the default(http://localhost:8080) or other network address, you can create `.env` file in the project directory and set `SERVER_PROXY`. + +*.env* + +``` +SERVER_PROXY=http://localhost:8080 +``` + +### Development server + +Run `npm start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +### Build + +Run `npm build` to build the project. The build artifacts will be stored in the `dist/` directory. + +### Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Implementation Progress + +### Pages + +| Name | Route | Module | UI | +| --- | ----- | ---------- | -- | +| Home | `/` | HomeModule | Y | +| Login | `/login` | LoginModule | Y | +| Job Manager | `/jobmanager` | JobManagerModule | Y | +| Interpreter Setting | `/interpreter` | InterpreterModule | Y | +| Notebook | `/notebook/{id}` | NotebookModule | Y | +| Notebook Repos | `/notebookRepos` | | | +| Credential | `/credential` | | | +| Helium | `/helium` | | WIP | +| Configuration | `/configuration` | | | + +### Notebook Features + +| Feature | Description | Status | +| ------ | ---- | ---- | +| Files System | Create/ Rename/ Import etc. | Y | +| Toolbar Actions | The top toolbar actions | Y | + +### Paragraph Features + +| Feature | Description | Status | +| ------ | ---- | ---- | +| Grid layout and resizable | | Y | +| Code Editor | | Y | +| Actions | The Corresponding actions of the drop-down menu in the setting button | Y | +| Actions(hot-keys) | Support hot-keys for the actions | WIP | +| Publishable | [publish paragraphs](http://zeppelin.apache.org/docs/0.8.0/usage/other_features/publishing_paragraphs.html) | | +| Stream | | | + +### Result Display + +| Type | Status | +| ------ | ---- | +| Dynamic Form | Y | +| Text | Y | +| Html | Y | +| Table | Y | +| Network | | + +### Table Visualization + +| Type | State | +| ------ | ---- | +| Line Chart | Y | +| Bard Chart | Y | +| Pie Chart | Y | +| Area Chart | Y | +| Scatter Chart | Y | + +### Helium Visualization + +| Type | Description | Status | +| ------ | ---- | ---- | +| Prototype | To verify the implementable prototype | Y | +| Publish Dependencies | Just like [zeppelin-vis](https://github.com/apache/zeppelin/tree/master/zeppelin-web/src/app/visualization) | WIP | +| Example Projects | | Y | +| Development Documents | | WIP | + +## Contributing + +### Dev Mode + +Follow the [Setup](#Setup) steps to starting the frontend service. The app will automatically reload if you change any of the source files. + +### Technologies + +Zeppelin-WEB-Angular is using Angular as the main Framework, before developing we hope highly recommended to have a good knowledge of [Angular](https://angular.io/) and [RxJs](https://github.com/ReactiveX/rxjs). + +In addition: + +- We use [G2](https://github.com/antvis/g2) [(MIT)](https://github.com/antvis/g2/blob/master/LICENSE) visualization +- We use [Lodash](https://lodash.com/) [(MIT)](https://github.com/lodash/lodash/blob/master/LICENSE) to process complex data +- We use [Monaco Editor](https://github.com/microsoft/monaco-editor) [(MIT)](https://github.com/microsoft/monaco-editor/blob/master/LICENSE.md) to make code editor + +### Coding style + +- We follow mainly the [Angular Style Guide](https://angular.io/guide/styleguide) +- We use a 2 spaces indentation +- We use single quotes + +But don't worry, TSLint and prettier will make you remember it for the most part. +Git hooks will automatically check and fix it when commit. + +### Folder Structure + +We follow mainly the [Workspace and project file structure](https://angular.io/guide/styleguide) to organize the folder structure and files. + +#### Src Folder Structure + +`src` folder contains the source code for Zeppelin-WEB-Angular. + +``` +├── app +│ ├── core +│ │ └── message-listener # handle WebSocket message +│ ├── interfaces # interfaces +│ ├── pages +│ │ ├── login # login module +│ │ └── workspace +│ │ ├── home # welcome module +│ │ ├── interpreter # interpreter settings +│ │ ├── job-manager # job manager module +│ │ └── notebook # notebook module +│ │ ├── action-bar # notebook settings +│ │ ├── interpreter-binding # interpreter binding +│ │ ├── permissions # permissions +│ │ └── paragraph # paragraph module +│ │ ├── code-editor # code editor module +│ │ ├── control # paragraph controls +│ │ ├── dynamic-forms # dynamic forms +│ │ └── result # display result +│ ├── sdk # Zeppelin API Frontend SDK +│ ├── share # Share Components +│ ├── services # API Service +│ └── visualization +│ ├── area-chart # Area Chart Component +│ ├── bar-chart # Bar Chart Component +│ ├── line-chart # Line Chart Component +│ ├── pie-chart # Pie Chart Component +│ ├── scatter-chart # Scatter Chart Component +│ └── table # Data Table Component +├── assets # Assets +└── styles + └── theme # Theme Files + ├── dark + └── light +``` + +#### Import Path Rules + +We specify path mapping in the `tsconfig.json` file to get a clear import path. + +So please follow the rules following: + +- Add `public-api.ts` and `index.ts` to the folder where want to export the modules +- `public-api.ts` File only included you wish to export modules +- `index.ts` File only export `./public-api.ts` +- Use relative paths instead of mapped paths when the same level to prevent circular references + +### Good Practices + +The following guide for this project only. Most of the time you only need to follow Angular's guide. + +#### Change Detection Strategy + +Use [OnPush](https://angular.io/api/core/ChangeDetectionStrategy#OnPush) as the change detection strategy for components. + +#### WebSocket Listen and Send + +*Send Message*: Inject the `MessageService` and then use its instance methods. + +```ts + +import { MessageService } from '@zeppelin/services'; + +export class SomeComponent { + + constructor(public messageService: MessageService) { } + + fun() { + // Do something + this.messageService.listNoteJobs(); + } +} +``` + +*Listen to Message* + +Make sure the class extends from `MessageListenersManager` and inject the `MessageService` and ensures that it is public. + +After that, you can use the `@MessageListener` decorator to decorate the corresponding message method. + +```ts +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { MessageService } from '@zeppelin/services'; +import { OP, ListNoteJobs } from '@zeppelin/sdk'; + +export class SomeComponent extends MessageListenersManager { + + constructor(public messageService: MessageService) { } + + @MessageListener(OP.LIST_NOTE_JOBS) + fun(data: ListNoteJobs) { + // Do something + } +} +``` + +#### Theming + +Use we provide the function to wrap component styles to implement theming. You can find the theme variables in the `src/styles/theme/` folder. + +```less +@import "theme-mixin"; + +.themeMixin({ + // component styles +}); +``` + +#### Imports order + +Follow of the following imports order: + +```ts +import * from '@angular/*' // Angular modules +import * from 'rxjs/*' // Rxjs modules +// BLANK LINE +import * from '*' // Other third party modules +// BLANK LINE +import * from '@zeppelin/*' // This project modules +// BLANK LINE +import * from './*' // Same level modules +``` \ No newline at end of file diff --git a/zeppelin-web-angular/WEB-INF/web.xml b/zeppelin-web-angular/WEB-INF/web.xml new file mode 100644 index 00000000000..f40bf861738 --- /dev/null +++ b/zeppelin-web-angular/WEB-INF/web.xml @@ -0,0 +1,41 @@ + + + + + + zeppelin-web-angular + + default + org.glassfish.jersey.servlet.ServletContainer + + jersey.config.server.provider.packages + org.apache.zeppelin.rest + + + 1 + + + + configuration + deployment + + + + + true + true + + + diff --git a/zeppelin-web-angular/angular.json b/zeppelin-web-angular/angular.json new file mode 100644 index 00000000000..37904c102f7 --- /dev/null +++ b/zeppelin-web-angular/angular.json @@ -0,0 +1,330 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "zeppelin": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "zeppelin", + "schematics": { + "@schematics/angular:component": { + "style": "less", + "skipTests": true, + "changeDetection": "OnPush" + }, + "ng-zorro-antd:component": { + "style": "less", + "skipTests": true, + "changeDetection": "OnPush", + "classnameWithModule": true + }, + "@schematics/angular:class": { + "skipTests": true + }, + "@schematics/angular:directive": { + "skipTests": true + }, + "@schematics/angular:guard": { + "skipTests": true + }, + "@schematics/angular:module": { + "skipTests": true + }, + "@schematics/angular:pipe": { + "skipTests": true + }, + "@schematics/angular:service": { + "skipTests": true + } + }, + "architect": { + "build": { + "builder": "ngx-build-plus:browser", + "options": { + "outputPath": "dist/zeppelin", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets", + { + "glob": "**/*", + "input": "./node_modules/mathjax", + "output": "/" + }, + { + "glob": "**/*", + "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", + "output": "/assets/" + }, + { + "glob": "**/*", + "input": "./WEB-INF", + "output": "/WEB-INF/" + } + ], + "styles": [ + "src/styles/theme/dark/antd-dark.less", + "src/styles/theme/light/antd-light.less", + "src/styles.less", + "./node_modules/highlight.js/styles/github.css", + "./node_modules/monaco-editor/min/vs/editor/editor.main.css" + ], + "stylePreprocessorOptions": { + "includePaths": [ + "src/styles/theme", + "src/styles/theme/dark", + "src/styles/theme/light" + ] + }, + "scripts": [ + "node_modules/mathjax/MathJax.js", + "node_modules/systemjs/dist/s.js", + "node_modules/systemjs/dist/extras/amd.js", + "node_modules/systemjs/dist/extras/named-register.js", + "node_modules/systemjs/dist/extras/use-default.js" + ] + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": false + } + } + }, + "serve": { + "builder": "ngx-build-plus:dev-server", + "options": { + "browserTarget": "zeppelin:build" + }, + "configurations": { + "production": { + "browserTarget": "zeppelin:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "zeppelin:build" + } + }, + "test": { + "builder": "ngx-build-plus:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.less" + ], + "scripts": [], + "assets": [ + "src/favicon.ico", + "src/assets" + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-e2e": { + "root": "e2e/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "zeppelin:serve" + }, + "configurations": { + "production": { + "devServerTarget": "zeppelin:serve:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-helium": { + "projectType": "library", + "root": "projects/zeppelin-helium", + "sourceRoot": "projects/zeppelin-helium/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/zeppelin-helium/tsconfig.lib.json", + "project": "projects/zeppelin-helium/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/zeppelin-helium/src/test.ts", + "tsConfig": "projects/zeppelin-helium/tsconfig.spec.json", + "karmaConfig": "projects/zeppelin-helium/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/zeppelin-helium/tsconfig.lib.json", + "projects/zeppelin-helium/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "helium-vis-example": { + "projectType": "library", + "root": "projects/helium-vis-example", + "sourceRoot": "projects/helium-vis-example/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/helium-vis-example/tsconfig.lib.json", + "project": "projects/helium-vis-example/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/helium-vis-example/src/test.ts", + "tsConfig": "projects/helium-vis-example/tsconfig.spec.json", + "karmaConfig": "projects/helium-vis-example/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/helium-vis-example/tsconfig.lib.json", + "projects/helium-vis-example/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-visualization": { + "projectType": "library", + "root": "projects/zeppelin-visualization", + "sourceRoot": "projects/zeppelin-visualization/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/zeppelin-visualization/tsconfig.lib.json", + "project": "projects/zeppelin-visualization/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/zeppelin-visualization/src/test.ts", + "tsConfig": "projects/zeppelin-visualization/tsconfig.spec.json", + "karmaConfig": "projects/zeppelin-visualization/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/zeppelin-visualization/tsconfig.lib.json", + "projects/zeppelin-visualization/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "zeppelin-sdk": { + "projectType": "library", + "root": "projects/zeppelin-sdk", + "sourceRoot": "projects/zeppelin-sdk/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-ng-packagr:build", + "options": { + "tsConfig": "projects/zeppelin-sdk/tsconfig.lib.json", + "project": "projects/zeppelin-sdk/ng-package.json" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "projects/zeppelin-sdk/src/test.ts", + "tsConfig": "projects/zeppelin-sdk/tsconfig.spec.json", + "karmaConfig": "projects/zeppelin-sdk/karma.conf.js" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "projects/zeppelin-sdk/tsconfig.lib.json", + "projects/zeppelin-sdk/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "defaultProject": "zeppelin" +} \ No newline at end of file diff --git a/zeppelin-web-angular/browserslist b/zeppelin-web-angular/browserslist new file mode 100644 index 00000000000..80848532e47 --- /dev/null +++ b/zeppelin-web-angular/browserslist @@ -0,0 +1,12 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/zeppelin-web-angular/e2e/protractor.conf.js b/zeppelin-web-angular/e2e/protractor.conf.js new file mode 100644 index 00000000000..1be6b530682 --- /dev/null +++ b/zeppelin-web-angular/e2e/protractor.conf.js @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// @ts-check +// Protractor configuration file, see link for more information +// https://github.com/angular/protractor/blob/master/lib/config.ts + +const { SpecReporter } = require('jasmine-spec-reporter'); + +/** + * @type { import("protractor").Config } + */ +exports.config = { + allScriptsTimeout: 11000, + specs: [ + './src/**/*.e2e-spec.ts' + ], + capabilities: { + 'browserName': 'chrome' + }, + directConnect: true, + baseUrl: 'http://localhost:4200/', + framework: 'jasmine', + jasmineNodeOpts: { + showColors: true, + defaultTimeoutInterval: 30000, + print: function() {} + }, + onPrepare() { + require('ts-node').register({ + project: require('path').join(__dirname, './tsconfig.json') + }); + jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); + } +}; \ No newline at end of file diff --git a/zeppelin-web-angular/e2e/src/app.e2e-spec.ts b/zeppelin-web-angular/e2e/src/app.e2e-spec.ts new file mode 100644 index 00000000000..d788f85250e --- /dev/null +++ b/zeppelin-web-angular/e2e/src/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import { AppPage } from './app.po'; +import { browser, logging } from 'protractor'; + +describe('workspace-project App', () => { + let page: AppPage; + + beforeEach(() => { + page = new AppPage(); + }); + + it('should display welcome message', () => { + page.navigateTo(); + expect(page.getTitleText()).toEqual('zeppelin app is running!'); + }); + + afterEach(async () => { + // Assert that there are no errors emitted from the browser + const logs = await browser.manage().logs().get(logging.Type.BROWSER); + expect(logs).not.toContain(jasmine.objectContaining({ + level: logging.Level.SEVERE, + } as logging.Entry)); + }); +}); diff --git a/zeppelin-web-angular/e2e/src/app.po.ts b/zeppelin-web-angular/e2e/src/app.po.ts new file mode 100644 index 00000000000..b8498c26f24 --- /dev/null +++ b/zeppelin-web-angular/e2e/src/app.po.ts @@ -0,0 +1,11 @@ +import { browser, by, element } from 'protractor'; + +export class AppPage { + navigateTo() { + return browser.get(browser.baseUrl) as Promise; + } + + getTitleText() { + return element(by.css('app-root .content span')).getText() as Promise; + } +} diff --git a/zeppelin-web-angular/e2e/tsconfig.json b/zeppelin-web-angular/e2e/tsconfig.json new file mode 100644 index 00000000000..39b800f7896 --- /dev/null +++ b/zeppelin-web-angular/e2e/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/e2e", + "module": "commonjs", + "target": "es5", + "types": [ + "jasmine", + "jasminewd2", + "node" + ] + } +} diff --git a/zeppelin-web-angular/karma.conf.js b/zeppelin-web-angular/karma.conf.js new file mode 100644 index 00000000000..67c6820c27b --- /dev/null +++ b/zeppelin-web-angular/karma.conf.js @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, './coverage/zeppelin'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json new file mode 100644 index 00000000000..46c0a074b8d --- /dev/null +++ b/zeppelin-web-angular/package-lock.json @@ -0,0 +1,15996 @@ +{ + "name": "zeppelin", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.803.14.tgz", + "integrity": "sha512-CPDDNTpM/9XWCFxCRL1/mYB54ivZcmWaVSjUgN2zcHWBc0gW3lrJrmmb+cJ1KSlOI7hoZaMTV1gWoX2QXd4JrA==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/build-angular": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.803.14.tgz", + "integrity": "sha512-AtrhLDcy5DHi5zWiahEmvbD6THkJkWv27TySTfpZlmMjpRJHNqK7uQiKR1iWSqo4VNpimFle3fwkfjQYHlEKqA==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "@angular-devkit/build-optimizer": "0.803.14", + "@angular-devkit/build-webpack": "0.803.14", + "@angular-devkit/core": "8.3.14", + "@babel/core": "7.5.5", + "@babel/preset-env": "7.5.5", + "@ngtools/webpack": "8.3.14", + "ajv": "6.10.2", + "autoprefixer": "9.6.1", + "browserslist": "4.6.6", + "cacache": "12.0.2", + "caniuse-lite": "1.0.30000989", + "circular-dependency-plugin": "5.2.0", + "clean-css": "4.2.1", + "copy-webpack-plugin": "5.0.4", + "core-js": "3.2.1", + "file-loader": "4.2.0", + "find-cache-dir": "3.0.0", + "glob": "7.1.4", + "istanbul-instrumenter-loader": "3.0.1", + "jest-worker": "24.9.0", + "karma-source-map-support": "1.4.0", + "less": "3.9.0", + "less-loader": "5.0.0", + "license-webpack-plugin": "2.1.2", + "loader-utils": "1.2.3", + "mini-css-extract-plugin": "0.8.0", + "minimatch": "3.0.4", + "open": "6.4.0", + "parse5": "4.0.0", + "postcss": "7.0.17", + "postcss-import": "12.0.1", + "postcss-loader": "3.0.0", + "raw-loader": "3.1.0", + "regenerator-runtime": "0.13.3", + "rxjs": "6.4.0", + "sass": "1.22.9", + "sass-loader": "7.2.0", + "semver": "6.3.0", + "source-map": "0.7.3", + "source-map-loader": "0.2.4", + "source-map-support": "0.5.13", + "speed-measure-webpack-plugin": "1.3.1", + "style-loader": "1.0.0", + "stylus": "0.54.5", + "stylus-loader": "3.0.2", + "terser": "4.3.8", + "terser-webpack-plugin": "1.4.1", + "tree-kill": "1.2.1", + "webpack": "4.39.2", + "webpack-dev-middleware": "3.7.0", + "webpack-dev-server": "3.8.0", + "webpack-merge": "4.2.1", + "webpack-sources": "1.4.3", + "webpack-subresource-integrity": "1.1.0-rc.6", + "worker-plugin": "3.2.0" + }, + "dependencies": { + "core-js": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz", + "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==", + "dev": true + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": 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" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "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==", + "dev": true + } + } + } + } + }, + "@angular-devkit/build-ng-packagr": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-ng-packagr/-/build-ng-packagr-0.803.14.tgz", + "integrity": "sha512-qIYLEOxL8kOmOVjisN0rSMGeN7D2TYc90k73LnXUtT8WL4a+bd6r8PNGrH9hrF8ABZ01oJ4PQi8kuE4Jm7+ptA==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/build-optimizer": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.803.14.tgz", + "integrity": "sha512-f1RYhO0swLfoLvCj/fUrDWm4vzVSnffcCc4C4PHnqoOGBRQpmIzG7G54Pm8YK677slioToYZQ68s3/zVtsQNWg==", + "dev": true, + "requires": { + "loader-utils": "1.2.3", + "source-map": "0.7.3", + "tslib": "1.10.0", + "typescript": "3.5.3", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.803.14.tgz", + "integrity": "sha512-hvxAyJzDCaIISATHcu0+rAAj7ZcmX7VREX6J3FUMYDxhdjKqe45Q5J6Oy/Df2ZSV3YxwySZVcIhrBstm+0LC7Q==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "@angular-devkit/core": "8.3.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular-devkit/core": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.3.14.tgz", + "integrity": "sha512-+IYLbtCxwIpaieRj0wurEXBzZ/fDSdWbyrCfajzDerzsxqghNcafAXSazHXWwISqtbr/pAOuqUNR+mEk2XBz3Q==", + "dev": true, + "requires": { + "ajv": "6.10.2", + "fast-json-stable-stringify": "2.0.0", + "magic-string": "0.25.3", + "rxjs": "6.4.0", + "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.3.14.tgz", + "integrity": "sha512-5gPmTBN85a2gTxz/FsM5fO9Bxw4KG6uJNLMDAWfPG8vvSQEl7J64ujyqxPz39TernQTEKeuhRC4I5H1aaW9I/Q==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "rxjs": "6.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@angular/animations": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.2.12.tgz", + "integrity": "sha512-QVtZUw5J9c0RcDaJntIoeWVk/q9dhjDFxh+yw/uPl9Z4upWASdsOpZU2lfjqyU0myfg8dnQyZa1+Ce7n/DaClQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/cdk": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-8.2.3.tgz", + "integrity": "sha512-ZwO5Sn720RA2YvBqud0JAHkZXjmjxM0yNzCO8RVtRE9i8Gl26Wk0j0nQeJkVm4zwv2QO8MwbKUKGTMt8evsokA==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^1.7.1" + } + }, + "@angular/cli": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-8.3.14.tgz", + "integrity": "sha512-cOP2UvnnYocx1U1aiNkuLCcBxSktIXkadzrY7UlWJtQiCPGWm3Y87BfrQXub9Nsh79iyV8k8uKZKEax2ayESSg==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.803.14", + "@angular-devkit/core": "8.3.14", + "@angular-devkit/schematics": "8.3.14", + "@schematics/angular": "8.3.14", + "@schematics/update": "0.803.14", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.1", + "debug": "^4.1.1", + "ini": "1.3.5", + "inquirer": "6.5.1", + "npm-package-arg": "6.1.0", + "npm-pick-manifest": "3.0.2", + "open": "6.4.0", + "pacote": "9.5.5", + "read-package-tree": "5.3.1", + "rimraf": "3.0.0", + "semver": "6.3.0", + "symbol-observable": "1.2.0", + "universal-analytics": "^0.4.20", + "uuid": "^3.3.2" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "@angular/common": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-8.2.12.tgz", + "integrity": "sha512-BNz1lo+PP+lwIX3sErRGBRnkMzT5yT8CJ5o/M29AanCdcx9dpoJG2WKgpIgw8UBcj9QlP0CkSmzPtUNtcNMthA==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-8.2.12.tgz", + "integrity": "sha512-V5mDWioGmSZ4cJJ2THo8qHYKwj3sUI7dpJ0oab2Al0FQAN8JCimWO6AQKRtjmnr78ZkMy9Xe/KK6ebl40ewL5Q==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler-cli": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-8.2.12.tgz", + "integrity": "sha512-OrNnkJ7OrpbcOtB4TWFBF6D3dtEfUuOQgfc3HBjizZuL8EuX0pU5dv4VTvLTRkmyUT/7fmmWdkEXJL+UQtXqPg==", + "dev": true, + "requires": { + "canonical-path": "1.0.0", + "chokidar": "^2.1.1", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.7.2", + "magic-string": "^0.25.0", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "source-map": "^0.6.1", + "tslib": "^1.9.0", + "yargs": "13.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": 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" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": 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" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "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=", + "dev": 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.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "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==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "yargs": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.1.0.tgz", + "integrity": "sha512-1UhJbXfzHiPqkfXNHYhiz79qM/kZqjTE8yGlEjZa85Q+3+OwcV6NRkV7XOV1W2Eom2bzILeUn55pQYffjVOLAg==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.0.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "@angular/core": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-8.2.12.tgz", + "integrity": "sha512-wEFwhHCuuXynXAMeA1G+0KIYY0jqXYs7I8p+GO+ufKoUmzWHFTvtMJ6nvKgy+LmZTByO2gf9oVAAlRodNb8ttQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/forms": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-8.2.12.tgz", + "integrity": "sha512-y1UObndCGbTYwLSzUWzCiX7th+mb4n712asApooGmfmIQmgTyHbKxYUJ9Ep1pgd0pqLBBnK249MQLH15NDpbyQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/language-service": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-8.2.12.tgz", + "integrity": "sha512-uXGVSC4ugkyBt7pYdI8qaKNV0TIxfjSWb3dWNuhD6b9riPtaa+xJFQrfMu7OX/tVX642aFxca4jkUHBLCyWptA==", + "dev": true + }, + "@angular/platform-browser": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-8.2.12.tgz", + "integrity": "sha512-VBvMjmFJapZ2pFlmxZiHtfPwbHp79RRi5mrdMhETjKMaLaC2tAR/99ijCpx2urDMqb/VDm7YHOtoLEpBFVDulg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-8.2.12.tgz", + "integrity": "sha512-O4krb+9tj028JOQHPgLk/87lyUlHt8dpNxzuYCT0G6kEmknjpyZBaxhvDPygGjGHXV3LDqlYVH+bh8ygJUhwmw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/router": { + "version": "8.2.12", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-8.2.12.tgz", + "integrity": "sha512-mq1FethFpYosSVzChstMpxZlL+oUFeaA+FrzZQL7zJP/mm61yFkkhoYGVG6pG0NWSzpJE4NY6YvGCvHgN4ZECw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@ant-design/colors": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.2.2.tgz", + "integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==", + "requires": { + "tinycolor2": "^1.4.1" + } + }, + "@ant-design/icons-angular": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons-angular/-/icons-angular-8.1.1.tgz", + "integrity": "sha512-JMfavPHwahJcGWT13bTCt4IHzrsNgbJzzB+VWYtzjwWszMCVkkOOn+aJbslupHOl72KWDvklN/LjCQPBgu7xLQ==", + "requires": { + "@ant-design/colors": "^3.1.0", + "tslib": "^1.9.0" + } + }, + "@antv/adjust": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.1.1.tgz", + "integrity": "sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/attr": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.1.2.tgz", + "integrity": "sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/component": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.3.8.tgz", + "integrity": "sha512-1WN3FzeRyJ1jraS/2og5gnm2ragnwtRMVQMiLolztWaUgC++F/B1CcSrPYfV1WvYrfuwbpX/QQxo3HL9aS+YJA==", + "requires": { + "@antv/attr": "~0.1.2", + "@antv/g": "~3.3.5", + "@antv/util": "~1.3.1", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/coord": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.1.0.tgz", + "integrity": "sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/data-set": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@antv/data-set/-/data-set-0.10.2.tgz", + "integrity": "sha512-FFWG5tiTiFiUrLDRwulraU5XfOdDjkYOlZna+AMT9FJw406D/gfS8eXM9YibscBH28M/+KLAVO8xEwuD1sc3bw==", + "requires": { + "@antv/hierarchy": "~0.4.0", + "@antv/util": "~1.3.1", + "d3-array": "~1.2.0", + "d3-composite-projections": "~1.2.0", + "d3-dsv": "~1.0.5", + "d3-geo": "~1.6.4", + "d3-geo-projection": "~2.1.2", + "d3-hexjson": "~1.0.1", + "d3-hierarchy": "~1.1.5", + "d3-sankey": "~0.7.1", + "d3-voronoi": "~1.1.2", + "dagre": "~0.8.2", + "point-at-length": "~1.0.2", + "regression": "~2.0.0", + "simple-statistics": "~6.1.0", + "topojson-client": "~3.0.0", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/g": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.3.6.tgz", + "integrity": "sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==", + "requires": { + "@antv/gl-matrix": "~2.7.1", + "@antv/util": "~1.3.1", + "d3-ease": "~1.0.3", + "d3-interpolate": "~1.1.5", + "d3-timer": "~1.0.6", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/g2": { + "version": "3.5.9", + "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-3.5.9.tgz", + "integrity": "sha512-AS0Exn9Khhx4Xp8JViv37/wjJbiC9zVY02hIdvUeTx4SaKC0nhE0euPfmthen1cQw7nVlGLYEGoav/qxpLAhiw==", + "requires": { + "@antv/adjust": "~0.1.0", + "@antv/attr": "~0.1.2", + "@antv/component": "~0.3.3", + "@antv/coord": "~0.1.0", + "@antv/g": "~3.3.6", + "@antv/scale": "~0.1.1", + "@antv/util": "~1.3.1", + "venn.js": "~0.2.20", + "wolfy87-eventemitter": "~5.1.0" + } + }, + "@antv/gl-matrix": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz", + "integrity": "sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==" + }, + "@antv/hierarchy": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@antv/hierarchy/-/hierarchy-0.4.0.tgz", + "integrity": "sha512-ols+m+Z8QA4895SWMTOSjVImOX4tEbWQTwJ0NE+WATc0WLSKs6D9y2yaR+ZWt6P60BMGVIKS6lIfabO3CwGgnQ==", + "requires": { + "@antv/util": "~1.3.1" + } + }, + "@antv/scale": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.1.3.tgz", + "integrity": "sha512-oknlOg4OUqIh8LygrfQttx+OAnNJm2fQ81si4g8aby1WJJwj/TU1gCr+J3loIpKBtBK4VpP/OzTTqg1Ym67SOQ==", + "requires": { + "@antv/util": "~1.3.1", + "fecha": "~2.3.3" + } + }, + "@antv/util": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-1.3.1.tgz", + "integrity": "sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==", + "requires": { + "@antv/gl-matrix": "^2.7.1" + } + }, + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.5.5.tgz", + "integrity": "sha512-i4qoSr2KTtce0DmkuuQBV4AuQgGPUcPXMr9L5MyYAtk06z068lQ10a4O009fe5OB/DfNV+h+qqT7ddNV8UnRjg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.5.5", + "@babel/helpers": "^7.5.5", + "@babel/parser": "^7.5.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", + "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "dev": true, + "requires": { + "@babel/types": "^7.6.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-define-map": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.5.5.tgz", + "integrity": "sha512-fTfxx7i0B5NJqvUOBBGREnrqbTxRh7zinBANpZXAVDlsZxYdclDp467G1sQ8VZYMnAURY3RpBUAgOYT9GfzHBg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.5.5.tgz", + "integrity": "sha512-5qZ3D1uMclSNqYcXqiHoA0meVdv+xUEex9em2fqMnrk/scphGlGgg66zjMrPJESPwrFJ6sbfFQYUSa0Mz7FabA==", + "dev": true, + "requires": { + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", + "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.5.5", + "lodash": "^4.17.13" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.5.5.tgz", + "integrity": "sha512-CkCYQLkfkiugbRDO8eZn6lRuR8kzZoGXCg3149iTk5se7g6qykSpy3+hELSwquhu+TgHn8nkLiBwHvNX8Hofcw==", + "dev": true, + "requires": { + "lodash": "^4.17.13" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz", + "integrity": "sha512-XvRFWrNnlsow2u7jXDuH4jDDctkxbS7gXssrP4q2nUD606ukXHRvydj346wmNg+zAgpFx4MWf4+usfC93bElJg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.5.5", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.5.5", + "@babel/types": "^7.5.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", + "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", + "dev": true, + "requires": { + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.2", + "@babel/types": "^7.6.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", + "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz", + "integrity": "sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz", + "integrity": "sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.6.2.tgz", + "integrity": "sha512-NxHETdmpeSCtiatMRYWVJo7266rrvAC3DTeG5exQBIH/fMIUK7ejDNznBbn3HQl/o9peymRRg7Yqkx6PdUXmMw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz", + "integrity": "sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz", + "integrity": "sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz", + "integrity": "sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.13" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.5.5.tgz", + "integrity": "sha512-U2htCNK/6e9K7jGyJ++1p5XRU+LJjrwtoiVn9SzRlDT2KubcZ11OOwy3s24TjHxPgxNwonCYP7U2K51uVYCMDg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.5.5", + "@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.5.5", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz", + "integrity": "sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.6.2.tgz", + "integrity": "sha512-KGKT9aqKV+9YMZSkowzYoYEiHqgaDhGmPNZlZxX6UeHC4z30nC1J9IrZuGqbYFB1jaIGdv91ujpze0exiVK8bA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz", + "integrity": "sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz", + "integrity": "sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", + "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz", + "integrity": "sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "babel-plugin-dynamic-import-node": "^2.3.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz", + "integrity": "sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw==", + "dev": true, + "requires": { + "regexpu-core": "^4.6.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz", + "integrity": "sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.5.5" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", + "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", + "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz", + "integrity": "sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.6.2.tgz", + "integrity": "sha512-orZI6cWlR3nk2YmYdb0gImrgCUwb5cBUwjf6Ks6dvNVvXERkwtJWOQaEOjPiu0Gu1Tq6Yq/hruCZZOOi9F34Dw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.6.0" + } + }, + "@babel/preset-env": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.5.5.tgz", + "integrity": "sha512-GMZQka/+INwsMz1A5UEql8tG015h5j/qjptpKY2gJ7giy8ohzU710YciJB5rcKsWGWHiW3RUnHib0E5/m3Tp3A==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-dynamic-import": "^7.5.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.5.5", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.5.0", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.5.5", + "@babel/plugin-transform-classes": "^7.5.5", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.5.0", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.5.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.5.0", + "@babel/plugin-transform-modules-commonjs": "^7.5.0", + "@babel/plugin-transform-modules-systemjs": "^7.5.0", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.5.5", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.5.5", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/runtime": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz", + "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "@babel/template": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" + } + }, + "@babel/traverse": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", + "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.3", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.3", + "@babel/types": "^7.6.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + } + }, + "@babel/types": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@ngtools/webpack": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-8.3.14.tgz", + "integrity": "sha512-eIU3W3T4YxiExkS/c09FkqQpnKeIuUFFnxyfdG40zospt28B6V5ZaEVw2z5+2CjxJlDUTUYZlhPiV9Rwadp3jg==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "enhanced-resolve": "4.1.0", + "rxjs": "6.4.0", + "tree-kill": "1.2.1", + "webpack-sources": "1.4.3" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, + "@schematics/angular": { + "version": "8.3.14", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.3.14.tgz", + "integrity": "sha512-1XXBh9+lowvltRlcCjDJa4GEr5Xq+uNJcxULHBaNY7YfQSwZ5KuyhTBWjCdKmMaTOV3pEcIHwyuNh26mpn98Bw==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "@angular-devkit/schematics": "8.3.14" + } + }, + "@schematics/update": { + "version": "0.803.14", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.803.14.tgz", + "integrity": "sha512-1erj7oaR2vKXo1DLE0s4BbbouBmgeAHEkPHQM7FPtyroZ18kytlT+qjTbsSnlRCwcFsjxmRkbRjXaXDz7ttsYQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.3.14", + "@angular-devkit/schematics": "8.3.14", + "@yarnpkg/lockfile": "1.1.0", + "ini": "1.3.5", + "pacote": "9.5.5", + "rxjs": "6.4.0", + "semver": "6.3.0", + "semver-intersect": "1.4.0" + }, + "dependencies": { + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "@types/date-fns": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/date-fns/-/date-fns-2.6.0.tgz", + "integrity": "sha1-sGLKRlYgApCb4MY6ZGftFzE2rME=", + "dev": true, + "requires": { + "date-fns": "*" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", + "dev": true + }, + "@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/highlight.js": { + "version": "9.12.3", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.3.tgz", + "integrity": "sha512-pGF/zvYOACZ/gLGWdQH8zSwteQS1epp68yRcVLJMgUck/MjEn/FBYmPub9pXT8C1e4a8YZfHo1CKyV8q1vKUnQ==", + "dev": true + }, + "@types/jasmine": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.3.16.tgz", + "integrity": "sha512-Nveep4zKGby8uIvG2AEUyYOwZS8uVeHK9TgbuWYSawUDDdIgfhCKz28QzamTo//Jk7Ztt9PO3f+vzlB6a4GV1Q==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.8.tgz", + "integrity": "sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg==", + "dev": true, + "requires": { + "@types/jasmine": "*" + } + }, + "@types/lodash": { + "version": "4.14.144", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", + "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", + "dev": true + }, + "@types/mathjax": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.35.tgz", + "integrity": "sha512-flo9bVJE2Lzv3X5NQXVhNhv7srqk//Ngr8MT+/jRErkWGYkk8EBm42J5W0XUH6p4nWF1iLGe+atSuIkR5wA2yw==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "8.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz", + "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/selenium-webdriver": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz", + "integrity": "sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA==", + "dev": true + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/tapable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.4.tgz", + "integrity": "sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.4.tgz", + "integrity": "sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==", + "dev": true, + "requires": { + "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==", + "dev": true + } + } + }, + "@types/webpack": { + "version": "4.39.5", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.39.5.tgz", + "integrity": "sha512-9twG6D97ao13MBLvigwfBJe6rxtb04UY3TcYHBYkW5sXZjUrNhqIRxLYg74VzK/YAE8xlVhOyd+3Whr7E5RrBA==", + "dev": true, + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "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==", + "dev": true + } + } + }, + "@types/webpack-sources": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.5.tgz", + "integrity": "sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "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==", + "dev": true + } + } + }, + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "abs-svg-path": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", + "integrity": "sha1-32Acjo0roQ1KdtYl4japo5wnI78=" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + }, + "adler-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", + "integrity": "sha1-aj5r8KY5ALoVZSgIyxXGgT0aXyU=", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, + "adm-zip": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz", + "integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "agentkeepalive": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", + "dev": true, + "requires": { + "humanize-ms": "^1.2.1" + } + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "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==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-escapes": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.2.1.tgz", + "integrity": "sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q==", + "dev": true, + "requires": { + "type-fest": "^0.5.2" + } + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "dev": true + }, + "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=" + }, + "ansi-to-html": { + "version": "0.6.12", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.12.tgz", + "integrity": "sha512-qBkIqLW979675mP76yB7yVkzeAWtATegdnDQ0RA3CZzknx0yUlNxMSML4xFdBfTs2GWYFQ1FELfbGbVSPzJ+LA==", + "requires": { + "entities": "^1.1.2" + } + }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "app-root-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz", + "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==", + "dev": true + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "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=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "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==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "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=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "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=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "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=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "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=", + "dev": true + }, + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz", + "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==", + "dev": true, + "requires": { + "browserslist": "^4.6.3", + "caniuse-lite": "^1.0.30000980", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.17", + "postcss-value-parser": "^4.0.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "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=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, + "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=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + }, + "dependencies": { + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "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=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz", + "integrity": "sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "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=", + "dev": true, + "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==", + "dev": true + } + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "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=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "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=", + "dev": true + } + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "kind-of": "^6.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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "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==", + "dev": true + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "blocking-proxy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "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" + } + }, + "boxen": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", + "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^2.4.2", + "cli-boxes": "^2.2.0", + "string-width": "^3.0.0", + "term-size": "^1.2.0", + "type-fest": "^0.3.0", + "widest-line": "^2.0.0" + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "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": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.6.tgz", + "integrity": "sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000984", + "electron-to-chromium": "^1.3.191", + "node-releases": "^1.1.25" + } + }, + "browserstack": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.5.3.tgz", + "integrity": "sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "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==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, + "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=", + "dev": true + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.2.tgz", + "integrity": "sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "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==", + "dev": true, + "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" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "http-cache-semantics": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", + "integrity": "sha512-TcIMG3qeVLgDr1TEd2XvHaTnMPwYQUQMIBLy+5pLSDKYFc7UIqj39w8EGzZkaxoLv/l2K8HaI0t5AVA+YYgUew==", + "dev": true + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + } + } + }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "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=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" + }, + "caniuse-lite": { + "version": "1.0.30000989", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz", + "integrity": "sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==", + "dev": true + }, + "canonical-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz", + "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "cfb": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.1.3.tgz", + "integrity": "sha512-joXBW0nMuwV9no7UTMiyVJnQL6XIU3ThXVjFUDHgl9MpILPOomyfaGqC290VELZ48bbQKZXnQ81UT5HouTxHsw==", + "requires": { + "adler-32": "~1.2.0", + "commander": "^2.16.0", + "crc-32": "~1.2.0", + "printj": "~1.1.2" + } + }, + "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" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.2.2.tgz", + "integrity": "sha512-bw3pm7kZ2Wa6+jQWYP/c7bAZy3i4GwiIiMO2EeRjrE48l8vBqC/WvFhSF0xyM8fQiPEGvwMY/5bqDG7sSEOuhg==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "circular-dependency-plugin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz", + "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "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==", + "dev": true + } + } + }, + "cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + }, + "dependencies": { + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "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=", + "dev": true + }, + "codelyzer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-5.2.0.tgz", + "integrity": "sha512-izfUfhEOOgAizszPlEDxo71DK/C4wprZw0vkY6UWcOSTQvN1JyfXf9DXwaV7WX+/JC+hH0ShXfdtGLA9Rca7LA==", + "dev": true, + "requires": { + "app-root-path": "^2.2.1", + "aria-query": "^3.0.0", + "axobject-query": "^2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "codepage": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", + "integrity": "sha1-jL4lSBMjVZ19MHVxsP/5HnodL5k=", + "requires": { + "commander": "~2.14.1", + "exit-on-epipe": "~1.0.1" + }, + "dependencies": { + "commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.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==", + "dev": true, + "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=", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "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==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "compare-versions": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.5.1.tgz", + "integrity": "sha512-9fGPIB7C6AyM18CJJBHt5EnCZDG3oiTJYy0NjfIAGjKpzv0tkxWko7TNQHF5ymqm7IH03tqmeuBxtvD+Izh6mg==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "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==", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz", + "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==", + "dev": true, + "requires": { + "mime-db": ">= 1.40.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "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==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "configstore": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", + "integrity": "sha512-CmquAXFBocrzaSM8mtGPMM/HiWmyIpr4CcJl/rgY2uCObZ/S7cKU0silxslqJejl+t/T9HS8E0PUNQD81JGUEQ==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "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==", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "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==", + "dev": true + }, + "contour_plot": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", + "integrity": "sha1-R1hw8DK44zhBKqX8UHiA8L9JXHc=" + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "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=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.0.4.tgz", + "integrity": "sha512-YBuYGpSzoCHSSDGyHy6VJ7SHojKp6WHT4D7ItcQFNAYx2hrwkMe56e97xfVR0/ovDuMTrMffXUiltvQljtAGeg==", + "dev": true, + "requires": { + "cacache": "^11.3.3", + "find-cache-dir": "^2.1.0", + "glob-parent": "^3.1.0", + "globby": "^7.1.1", + "is-glob": "^4.0.1", + "loader-utils": "^1.2.3", + "minimatch": "^3.0.4", + "normalize-path": "^3.0.0", + "p-limit": "^2.2.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.7.0", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "cacache": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.3.tgz", + "integrity": "sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==", + "dev": true, + "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" + } + }, + "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==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + } + } + }, + "core-js": { + "version": "2.6.10", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz", + "integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==" + }, + "core-js-compat": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.3.3.tgz", + "integrity": "sha512-GNZkENsx5pMnS7Inwv7ZO/s3B68a9WU5kIjxqrD/tkNR8mtfXJRk8fAKRlbvWZSGPc59/TkiOBDYl5Cb65pTVA==", + "dev": true, + "requires": { + "browserslist": "^4.7.1", + "semver": "^6.3.0" + }, + "dependencies": { + "browserslist": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.2.tgz", + "integrity": "sha512-uZavT/gZXJd2UTi9Ov7/Z340WOSQ3+m1iBVRUknf+okKxonL9P83S3ctiBDtuRmRu8PiCHjqyueqQ9HYlJhxiw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001004", + "electron-to-chromium": "^1.3.295", + "node-releases": "^1.1.38" + } + }, + "caniuse-lite": { + "version": "1.0.30001004", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001004.tgz", + "integrity": "sha512-3nfOR4O8Wa2RWoYfJkMtwRVOsK96TQ+eq57wd0iKaEWl8dwG4hKZ/g0MVBfCvysFvMLi9fQGR/DvozMdkEPl3g==", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + } + }, + "crc-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.0.tgz", + "integrity": "sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==", + "requires": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "css-parse": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", + "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", + "dev": true + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" + }, + "d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + }, + "d3-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz", + "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg==" + }, + "d3-composite-projections": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/d3-composite-projections/-/d3-composite-projections-1.2.3.tgz", + "integrity": "sha512-RxNBoRGf3epTnQBUKeEpaXpD8BA/Ud0xRuLwWxyI7dWfuuYgJZMKw6ZsZOwfDNC0ZbMWaU0eBFlL05A2jlcsWg==", + "requires": { + "d3-geo": "^1.11.6", + "d3-path": "^1.0.7" + }, + "dependencies": { + "d3-geo": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.6.tgz", + "integrity": "sha512-z0J8InXR9e9wcgNtmVnPTj0TU8nhYT6lD/ak9may2PdKqXIeHUr8UbFLoCtrPYNsjv6YaLvSDQVl578k6nm7GA==", + "requires": { + "d3-array": "1" + } + } + } + }, + "d3-dispatch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.5.tgz", + "integrity": "sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g==" + }, + "d3-dsv": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.10.tgz", + "integrity": "sha512-vqklfpxmtO2ZER3fq/B33R/BIz3A1PV0FaZRuFM8w6jLo7sUX1BZDh73fPlr0s327rzq4H6EN1q9U+eCBCSN8g==", + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + } + }, + "d3-ease": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.5.tgz", + "integrity": "sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ==" + }, + "d3-geo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.6.4.tgz", + "integrity": "sha1-8g4eRhyxhF9ai+Vatvh2VCp+MZk=", + "requires": { + "d3-array": "1" + } + }, + "d3-geo-projection": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.1.2.tgz", + "integrity": "sha1-ffjh6dBG1jHGUJ9+UxNX1K3CSqM=", + "requires": { + "commander": "2", + "d3-array": "1", + "d3-geo": "^1.1.0" + } + }, + "d3-hexjson": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d3-hexjson/-/d3-hexjson-1.0.1.tgz", + "integrity": "sha512-TeH4T0PSbDazMm3gHgc4ulO0PfrZpz0Uk3y5tCGz+NgC7HnX7KBdem7uAN+j9x3ZshTh7raN3V/bFhaLB2C8DA==", + "requires": { + "d3-array": "1" + } + }, + "d3-hierarchy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz", + "integrity": "sha512-L+GHMSZNwTpiq4rt9GEsNcpLa4M96lXMR8M/nMG9p5hBE0jy6C+3hWtyZMenPQdwla249iJy7Nx0uKt3n+u9+w==" + }, + "d3-interpolate": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.8.tgz", + "integrity": "sha512-J6EfUNwcMQ+aM5YPOB8ZbgAZu6wc82f/0WFxrxwV6Ll8wBwLaHLKCqQ5Imub02JriCVVdPjgI+6P3a4EWJCxAg==" + }, + "d3-sankey": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.7.1.tgz", + "integrity": "sha1-0imDImj8aaf+yEgD6WwiVqYUxSE=", + "requires": { + "d3-array": "1", + "d3-collection": "1", + "d3-shape": "^1.2.0" + } + }, + "d3-selection": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.0.tgz", + "integrity": "sha512-EYVwBxQGEjLCKF2pJ4+yrErskDnz5v403qvAid96cNdCMr8rmCYfY5RGzWz24mdIbxmDf6/4EAH+K9xperD5jg==" + }, + "d3-shape": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.5.tgz", + "integrity": "sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg==", + "requires": { + "d3-path": "1" + } + }, + "d3-timer": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.9.tgz", + "integrity": "sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg==" + }, + "d3-transition": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.2.0.tgz", + "integrity": "sha512-VJ7cmX/FPIPJYuaL2r1o1EMHLttvoIuZhhuAlRoOxDzogV8iQS6jYulDm3xEU3TqL80IZIhI551/ebmCMrkvhw==", + "requires": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" + } + }, + "d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" + }, + "dagre": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.4.tgz", + "integrity": "sha512-Dj0csFDrWYKdavwROb9FccHfTC4fJbyF/oJdL9LNZJ8WUvl968P6PAKEriGqfbdArVJEmmfA+UyumgWEwcHU6A==", + "requires": { + "graphlib": "^2.1.7", + "lodash": "^4.17.4" + } + }, + "damerau-levenshtein": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz", + "integrity": "sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==" + }, + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "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=", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + } + }, + "defer-to-connect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.0.2.tgz", + "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "kind-of": "^6.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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "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=", + "dev": true + } + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "dependency-graph": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz", + "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "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=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "dev": true + }, + "dezalgo": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-match-patch": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz", + "integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg==" + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "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=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^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==", + "dev": true + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "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=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.295", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.295.tgz", + "integrity": "sha512-KxlGE9GcZTv7xGwYJGMEABHJq2JuTMNF7jD8NwHk6sBY226mW+Dyp9kZmA2Od9tKHMCS7ltPnqFg+zq3jTWN7Q==", + "dev": true + }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, + "elliptic": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "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==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + }, + "dependencies": { + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "err-code": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", + "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "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=" + }, + "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==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "eventsource": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", + "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "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" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": 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": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "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.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "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=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": 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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "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==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "kind-of": "^6.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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "figures": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-loader": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.2.0.tgz", + "integrity": "sha512-+xZnaK5R8kBJrHK0/6HRlrKNamvVS5rjyuju+rnyxRGuwUJwpAMsVzUl5dz6rK8brkzjV6JpcFNjp6NqV0g1OQ==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "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==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "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==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.0.0.tgz", + "integrity": "sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.0", + "pkg-dir": "^4.1.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + } + } + }, + "find-parent-dir": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", + "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flatted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", + "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "fmin": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", + "integrity": "sha1-Wbu0DUP/3ByUzQClaMQflfGXMBc=", + "requires": { + "contour_plot": "^0.0.1", + "json2module": "^0.0.3", + "rollup": "^0.25.8", + "tape": "^4.5.1", + "uglify-js": "^2.6.2" + } + }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, + "follow-redirects": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", + "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "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=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "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=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "^1.0.0" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.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=", + "dev": true, + "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": "2.1.1", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz", + "integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==", + "dev": 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==" + }, + "g-status": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", + "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "matcher": "^1.0.0", + "simple-git": "^1.85.0" + } + }, + "genfun": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", + "dev": true + }, + "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==", + "dev": true + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz", + "integrity": "sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA==", + "dev": true + }, + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", + "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", + "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-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": 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=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "dir-glob": "^2.0.0", + "glob": "^7.1.2", + "ignore": "^3.3.5", + "pify": "^3.0.0", + "slash": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "graphlib": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.7.tgz", + "integrity": "sha512-TyI9jIy2J4j0qgPmOOrHTCtpPqJGN/aurBwc6ZT+bRii+di1I+Wv3obRhVrmBEXet+qkMaEX67dXrwsd3QQM6w==", + "requires": { + "lodash": "^4.17.5" + } + }, + "handle-thing": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz", + "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==", + "dev": true + }, + "handlebars": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.5.tgz", + "integrity": "sha512-0Ce31oWVB7YidkaTq33ZxEbN+UDxMMgThvCe8ptgQViymL5DPis9uLdTA13MiRPhgvqyxIegugrP97iK3JeBHg==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "uglify-js": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.4.tgz", + "integrity": "sha512-9Yc2i881pF4BPGhjteCXQNaXx1DCwm3dtOyBaG2hitHjLWOczw/ki8vD1bqyT3u6K0Ms/FpCShkmfg+FtlOfYA==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + } + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "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" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "highlight.js": { + "version": "9.15.10", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz", + "integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==" + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "dev": true + }, + "http-proxy": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", + "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "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=", + "dev": true + }, + "https-proxy-agent": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.3.tgz", + "integrity": "sha512-Ytgnz23gm2DVftnzqRRz2dOXZbGd2uiajSw/95bPp6v53zPRspQjLm/AfBgqbJ2qfeRXWIOMVLpp86+/5yX39Q==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "husky": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-2.7.0.tgz", + "integrity": "sha512-LIi8zzT6PyFpcYKdvWRCn/8X+6SuG2TgYYMrM6ckEYhlp44UcEduVymZGIZNLiwOUjrEud+78w/AsAiqJA/kRg==", + "dev": true, + "requires": { + "cosmiconfig": "^5.2.0", + "execa": "^1.0.0", + "find-up": "^3.0.0", + "get-stdin": "^7.0.0", + "is-ci": "^2.0.0", + "pkg-dir": "^4.1.0", + "please-upgrade-node": "^3.1.1", + "read-pkg": "^5.1.1", + "run-node": "^1.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "pkg-dir": "^3.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=", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "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.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "injection-js": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.2.2.tgz", + "integrity": "sha512-9K4fW2NNPG3JCvORx5G/T6q/PZYIr43RFgxBvtk3OV4omh5iqvpK4cChuBfhgPnRbXSgZRfuROh0XG5KNA8Xlg==", + "dev": true + }, + "inquirer": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.1.tgz", + "integrity": "sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^2.4.2", + "cli-cursor": "^3.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^4.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==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz", + "integrity": "sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^5.2.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "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==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", + "dev": true + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "binary-extensions": "^2.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.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.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=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "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==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "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=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + }, + "dependencies": { + "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=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + } + } + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "is-npm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", + "integrity": "sha512-wsigDr1Kkschp2opC4G3yA6r9EgVA6NjRpWzIi9axXqeIaAATPRJc4uLujXe3Nd9uO8KoDyA4MD6aZSeXTADhA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "dev": true, + "requires": { + "symbol-observable": "^1.1.0" + } + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + } + }, + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-reference": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", + "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39" + } + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "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==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isbinaryfile": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.6.tgz", + "integrity": "sha512-x0Eicp6KsShG1k1rMgBAi/1GgY7kFGEBwQpw3PXGEmu+rBcBNhqU8g2DgY9mlepAsLPzrzrbqSgCGANnki4POA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "compare-versions": "^3.4.0", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-hook": "^2.0.7", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.4", + "js-yaml": "^3.13.1", + "make-dir": "^2.1.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + } + } + } + }, + "istanbul-instrumenter-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz", + "integrity": "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w==", + "dev": true, + "requires": { + "convert-source-map": "^1.5.0", + "istanbul-lib-instrument": "^1.7.3", + "loader-utils": "^1.1.0", + "schema-utils": "^0.3.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "^5.0.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==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz", + "integrity": "sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA==", + "dev": true, + "requires": { + "append-transform": "^1.0.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==", + "dev": true, + "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" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "dev": true, + "requires": { + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" + }, + "dependencies": { + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.4.0.tgz", + "integrity": "sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", + "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "dev": true, + "requires": { + "colors": "1.1.2" + } + }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "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=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "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==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "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==", + "dev": true + }, + "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=", + "dev": true + }, + "json2module": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", + "integrity": "sha1-APtfSpt638PwZHwpyxe80Zeb6bI=", + "requires": { + "rw": "^1.3.2" + } + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jszip": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.2.2.tgz", + "integrity": "sha512-NmKajvAFQpbg3taXQXr/ccS2wcucR1AZ+NtyWp2Nq7HHVsXhcJFR8p0Baf32C2yVvBylFWVeKf+WI2AnvlPhpA==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "karma": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-4.1.0.tgz", + "integrity": "sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw==", + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "braces": "^2.3.2", + "chokidar": "^2.0.3", + "colors": "^1.1.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.11", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.3.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": 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==", + "dev": 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" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "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=", + "dev": 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.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "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=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": 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==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "dev": true, + "requires": { + "fs-access": "^1.0.0", + "which": "^1.2.1" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.6.tgz", + "integrity": "sha512-WFh77RI8bMIKdOvI/1/IBmgnM+Q7NOLhnwG91QJrM8lW+CIXCjTzhhUsT/svLvAkLmR10uWY4RyYbHMLkTglvg==", + "dev": true, + "requires": { + "istanbul-api": "^2.1.6", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", + "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", + "dev": true, + "requires": { + "jasmine-core": "^3.3" + } + }, + "karma-jasmine-html-reporter": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.4.2.tgz", + "integrity": "sha512-7g0gPj8+9JepCNJR9WjDyQ2RkZ375jpdurYQyAYv8PorUCadepl8vrD6LmMqOGcM17cnrynBawQYZHaumgDjBw==", + "dev": true + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "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" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.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==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "less": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/less/-/less-3.9.0.tgz", + "integrity": "sha512-31CmtPEZraNUtuUREYjSqRkeETFdyEHSEPAGq4erDlUXtda7pzNmctdljdIagSb589d/qXGWiiP31R5JVf+v0w==", + "dev": true, + "requires": { + "clone": "^2.1.2", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "mime": "^1.4.1", + "mkdirp": "^0.5.0", + "promise": "^7.1.1", + "request": "^2.83.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==", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-5.0.0.tgz", + "integrity": "sha512-bquCU89mO/yWLaUq0Clk7qCsKhsF/TZpJUzETRvJa9KSVEL9SO3ovCvdEHISBhrC81OwC8QSVX7E0bzElZj9cg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^4.0.1" + } + }, + "less-plugin-npm-import": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/less-plugin-npm-import/-/less-plugin-npm-import-2.1.0.tgz", + "integrity": "sha1-gj5phskzGKmBccqFiEi2vq1Vvz4=", + "dev": true, + "requires": { + "promise": "~7.0.1", + "resolve": "~1.1.6" + }, + "dependencies": { + "promise": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.0.4.tgz", + "integrity": "sha1-Nj6EpMNsg1a4kP7WLJHOhdAu1Tk=", + "dev": true, + "requires": { + "asap": "~2.0.3" + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "license-webpack-plugin": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.1.2.tgz", + "integrity": "sha512-7poZHRla+ae0eEButlwMrPpkXyhNVBf2EHePYWT0jyLnI6311/OXJkTI2sOIRungRpQgU2oDMpro5bSFPT5F0A==", + "dev": true, + "requires": { + "@types/webpack-sources": "^0.1.5", + "webpack-sources": "^1.2.0" + } + }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "lines-and-columns": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "lint-staged": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.2.1.tgz", + "integrity": "sha512-n0tDGR/rTCgQNwXnUf/eWIpPNddGWxC32ANTNYsj2k02iZb7Cz5ox2tytwBu+2r0zDXMEMKw7Y9OD/qsav561A==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "commander": "^2.14.1", + "cosmiconfig": "^5.2.0", + "debug": "^3.1.0", + "dedent": "^0.7.0", + "del": "^3.0.0", + "execa": "^1.0.0", + "g-status": "^2.0.2", + "is-glob": "^4.0.0", + "is-windows": "^1.0.2", + "listr": "^0.14.2", + "listr-update-renderer": "^0.5.0", + "lodash": "^4.17.11", + "log-symbols": "^2.2.0", + "micromatch": "^3.1.8", + "npm-which": "^3.0.1", + "p-map": "^1.1.1", + "path-is-inside": "^1.0.2", + "pify": "^3.0.0", + "please-upgrade-node": "^3.0.2", + "staged-git-files": "1.1.2", + "string-argv": "^0.0.2", + "stringify-object": "^3.2.2", + "yup": "^0.27.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "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" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "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=", + "dev": true + } + } + }, + "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=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "requires": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "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==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.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==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "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==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.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==", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + } + } + } + }, + "log4js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "dev": true, + "requires": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.4", + "streamroller": "^1.0.6" + } + }, + "loglevel": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz", + "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "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==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz", + "integrity": "sha512-6QK0OpF/phMz0Q2AxILkX2mFhi7m+WMwTRg0LQKq/WBB0cDP4rYH3Wp4/d3OTXlrPLVJT/RFqj8tFeAR4nk8AA==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "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==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "make-fetch-happen": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.1.tgz", + "integrity": "sha512-b4dfaMvUDR67zxUq1+GN7Ke9rH5WvGRmoHuMH7l+gmUCR2tCXFP6mpeJ9Dp+jB6z8mShRopSf1vLRBhRs8Cu5w==", + "dev": true, + "requires": { + "agentkeepalive": "^3.4.1", + "cacache": "^12.0.0", + "http-cache-semantics": "^3.8.1", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "node-fetch-npm": "^2.0.2", + "promise-retry": "^1.1.1", + "socks-proxy-agent": "^4.0.0", + "ssri": "^6.0.0" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", + "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.4" + } + }, + "mathjax": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", + "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==" + }, + "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==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "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=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": 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": { + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": 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" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz", + "integrity": "sha512-MNpRGbNA52q6U92i0qbVpQNsgk7LExy41MdAlG84FeytfDOtRIf/mCHdEgG8rpTKOaNKiqUnZdlptF469hxqOw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "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==", + "dev": true + }, + "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=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "monaco-editor": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.18.1.tgz", + "integrity": "sha512-fmL+RFZ2Hrezy+X/5ZczQW51LUmvzfcqOurnkCIRFTyjdVjzR7JvENzI6+VKBJzJdPh6EYL4RoWl92b2Hrk9fw==" + }, + "monaco-editor-webpack-plugin": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.7.0.tgz", + "integrity": "sha512-oItymcnlL14Sjd7EF7q+CMhucfwR/2BxsqrXIBrWL6LQplFfAfV+grLEQRmVHeGSBZ/Gk9ptzfueXnWcoEcFuA==", + "dev": true, + "requires": { + "@types/webpack": "^4.4.19" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "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.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "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=", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "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": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "ng-packagr": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-5.7.0.tgz", + "integrity": "sha512-/75eqAyk2ef8J0aMLl7XCx1QXmqUUTsQDu+fNCFDIYpkpWBh0C8Rkdd72hMLPv3MMo63pfaNeiMXa0zzpQINyA==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "autoprefixer": "^9.6.0", + "browserslist": "^4.0.0", + "chalk": "^2.3.1", + "chokidar": "^3.0.0", + "clean-css": "^4.1.11", + "commander": "^3.0.0", + "fs-extra": "^8.0.0", + "glob": "^7.1.2", + "injection-js": "^2.2.1", + "less": "^3.8.0", + "less-plugin-npm-import": "^2.1.0", + "node-sass-tilde-importer": "^1.0.0", + "postcss": "^7.0.0", + "postcss-url": "^8.0.0", + "read-pkg-up": "^5.0.0", + "rimraf": "^3.0.0", + "rollup": "^1.12.1", + "rollup-plugin-commonjs": "^10.0.0", + "rollup-plugin-json": "^4.0.0", + "rollup-plugin-node-resolve": "^5.0.0", + "rollup-plugin-sourcemaps": "^0.4.2", + "rxjs": "^6.0.0", + "sass": "^1.17.3", + "stylus": "^0.54.5", + "terser": "^4.1.2", + "update-notifier": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "rimraf": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz", + "integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "1.25.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.25.2.tgz", + "integrity": "sha512-+7z6Wab/L45QCPcfpuTZKwKiB0tynj05s/+s2U3F2Bi7rOLPr9UcjUwO7/xpjlPNXA/hwnth6jBExFRGyf3tMg==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/node": "*", + "acorn": "^7.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ng-zorro-antd": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/ng-zorro-antd/-/ng-zorro-antd-8.4.1.tgz", + "integrity": "sha512-P/EpGpqRRsx2NmyJyulhH56jNYV2a1e1lf9F2NOp1IIG3J1XKFAxHPCetaGeeeEbXT2voQWshD12iTf2Fb0xAQ==", + "requires": { + "@angular/cdk": "^8.0.0", + "@ant-design/icons-angular": "^8.0.2", + "date-fns": "^1.30.1", + "tslib": "^1.9.0" + } + }, + "ngx-build-plus": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/ngx-build-plus/-/ngx-build-plus-8.1.5.tgz", + "integrity": "sha512-jkMN43wBqCqIBYKnQwf+NiZYgbYY1nNTs/Jg41lt7mc9nxBQobs3Cypty3Hy22m9caFLWQR+3AQIttxmr3o9NA==", + "dev": true, + "requires": { + "@schematics/angular": "8.0.0", + "cross-spawn": "^6.0.5", + "rxjs": "6.4.0", + "webpack-dev-server": "^3.1.14", + "webpack-merge": "^4.2.1" + }, + "dependencies": { + "@angular-devkit/core": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-8.0.0.tgz", + "integrity": "sha512-wYf4zzpYj5Y673DG8iteK0GsDDuXBKN/TOXm4lUwmXcz8QHTD+BfR6qA5TBDqlMGpU7CP1/0vgbv2px17CDETQ==", + "dev": true, + "requires": { + "ajv": "6.10.0", + "fast-json-stable-stringify": "2.0.0", + "magic-string": "0.25.2", + "rxjs": "6.4.0", + "source-map": "0.7.3" + } + }, + "@angular-devkit/schematics": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-8.0.0.tgz", + "integrity": "sha512-IXJOs/DkDqNbfG76sNNY5ePZ37rjkMUopmtvhN6/U1hQFwTpGa9N0bCHFphcKraXeS6Jfox5XwFEStc/1xyhfw==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.0.0", + "rxjs": "6.4.0" + } + }, + "@schematics/angular": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-8.0.0.tgz", + "integrity": "sha512-c/cFpe+u7Xh4xX3/kn9BSRY4YhdO0OsDbRK0pGLDJFFs5JGvwoURtNXn4/4dVlsj3PWyNhxK0Ljl3dyw3NQBHA==", + "dev": true, + "requires": { + "@angular-devkit/core": "8.0.0", + "@angular-devkit/schematics": "8.0.0" + } + }, + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "magic-string": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.2.tgz", + "integrity": "sha512-iLs9mPjh9IuTtRsqqhNGYcZXGei0Nh/A4xirrsqW7c+QhKVFL2vm7U09ru6cHRD22azaP/wMDgI+HCqbETMTtg==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, + "rxjs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", + "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-fetch-npm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "json-parse-better-errors": "^1.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node-forge": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", + "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", + "dev": true + }, + "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==", + "dev": true, + "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": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.38", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.38.tgz", + "integrity": "sha512-/5NZAaOyTj134Oy5Cp/J8mso8OD/D9CSuL+6TOXXsTKO8yjc5e4up75SRPCganCjwFKMj2jbp5tR0dViVdox7g==", + "dev": true, + "requires": { + "semver": "^6.3.0" + } + }, + "node-sass-tilde-importer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/node-sass-tilde-importer/-/node-sass-tilde-importer-1.0.2.tgz", + "integrity": "sha512-Swcmr38Y7uB78itQeBm3mThjxBy9/Ah/ykPIaURY/L6Nec9AyRoL/jJ7ECfMR+oZeCTVQNxVMu/aHU+TLRVbdg==", + "dev": true, + "requires": { + "find-parent-dir": "^0.3.0" + } + }, + "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==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "npm-bundled": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", + "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", + "dev": true + }, + "npm-package-arg": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.0.tgz", + "integrity": "sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.6.0", + "osenv": "^0.1.5", + "semver": "^5.5.0", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "npm-packlist": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.6.tgz", + "integrity": "sha512-u65uQdb+qwtGvEJh/DgQgW1Xg7sqeNbmxYyrvlNznaVTjV3E5P6F/EFjM+BVHXl7JJlsdG8A64M0XI8FI/IOlg==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npm-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", + "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "dev": true, + "requires": { + "which": "^1.2.10" + } + }, + "npm-pick-manifest": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "npm-registry-fetch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz", + "integrity": "sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A==", + "dev": true, + "requires": { + "JSONStream": "^1.3.4", + "bluebird": "^3.5.1", + "figgy-pudding": "^3.4.1", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "npm-package-arg": "^6.1.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } + } + }, + "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=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "dev": true, + "requires": { + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "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=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==" + }, + "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=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "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==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-6.4.0.tgz", + "integrity": "sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, + "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + } + } + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.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=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "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==", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "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==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.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==", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + } + }, + "pacote": { + "version": "9.5.5", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.5.tgz", + "integrity": "sha512-jAEP+Nqj4kyMWyNpfTU/Whx1jA7jEc5cCOlurm0/0oL+v8TAp1QSsK83N7bYe+2bEdFzMAtPG5TBebjzzGV0cA==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "cacache": "^12.0.2", + "figgy-pudding": "^3.5.1", + "get-stream": "^4.1.0", + "glob": "^7.1.3", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "make-fetch-happen": "^5.0.0", + "minimatch": "^3.0.4", + "minipass": "^2.3.5", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "normalize-package-data": "^2.4.0", + "npm-package-arg": "^6.1.0", + "npm-packlist": "^1.1.12", + "npm-pick-manifest": "^2.2.3", + "npm-registry-fetch": "^4.0.0", + "osenv": "^0.1.5", + "promise-inflight": "^1.0.1", + "promise-retry": "^1.1.1", + "protoduck": "^5.0.1", + "rimraf": "^2.6.2", + "safe-buffer": "^5.1.2", + "semver": "^5.6.0", + "ssri": "^6.0.1", + "tar": "^4.4.8", + "unique-filename": "^1.1.1", + "which": "^1.3.1" + }, + "dependencies": { + "npm-pick-manifest": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-2.2.3.tgz", + "integrity": "sha512-+IluBC5K201+gRU85vFlUwX3PFShZAbAgDNp2ewJdWMVSppdo/Zih0ul2Ecky/X7b51J7LrrUAP+XOmOCvYZqA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "npm-package-arg": "^6.0.0", + "semver": "^5.4.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha1-en7A0esG+lMlx9PgCbhZoJtdSes=" + }, + "parse5": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", + "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", + "optional": true + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "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==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "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=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "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=", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "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=", + "dev": true + }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "point-at-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/point-at-length/-/point-at-length-1.0.2.tgz", + "integrity": "sha1-kXbY1tfIFi8Stkb3B9ufDqcoEl4=", + "requires": { + "abs-svg-path": "~0.1.1", + "isarray": "~0.0.1", + "parse-svg-path": "~0.1.1" + } + }, + "portfinder": { + "version": "1.0.25", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", + "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "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=", + "dev": true + }, + "postcss": { + "version": "7.0.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.17.tgz", + "integrity": "sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^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==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-import": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz", + "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==", + "dev": true, + "requires": { + "postcss": "^7.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "dependencies": { + "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==", + "dev": true + } + } + }, + "postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "dev": true, + "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==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "schema-utils": "^1.0.0" + } + }, + "postcss-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-8.0.0.tgz", + "integrity": "sha512-E2cbOQ5aii2zNHh8F6fk1cxls7QVFZjLPSrqvmiza8OuXLzIpErij8BDS5Y3STPfJgpIMNCPEr8JlKQWEoozUw==", + "dev": true, + "requires": { + "mime": "^2.3.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.0", + "postcss": "^7.0.2", + "xxhashjs": "^0.2.1" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + } + } + }, + "postcss-value-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "prettier": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", + "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", + "dev": true + }, + "printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "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==", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "optional": true, + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", + "dev": true, + "requires": { + "err-code": "^1.0.0", + "retry": "^0.10.0" + }, + "dependencies": { + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + } + } + }, + "property-expr": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", + "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", + "dev": true + }, + "protoduck": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", + "dev": true, + "requires": { + "genfun": "^5.0.0" + } + }, + "protractor": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.2.tgz", + "integrity": "sha512-zlIj64Cr6IOWP7RwxVeD8O4UskLYPoyIcg0HboWJL9T79F1F0VWtKkGTr/9GN6BKL+/Q/GmM7C9kFVCfDbP5sA==", + "dev": true, + "requires": { + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "optimist": "~0.6.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.0.6" + }, + "dependencies": { + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "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=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "source-map": "^0.5.6" + } + }, + "webdriver-manager": { + "version": "12.1.7", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.7.tgz", + "integrity": "sha512-XINj6b8CYuUYC93SG3xPkxlyUc3IJbD6Vvo75CVGuG9uzsefDzWQrhz0Lq8vbPxtb4d63CZdYophF8k8Or/YiA==", + "dev": true, + "requires": { + "adm-zip": "^0.4.9", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + } + } + } + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "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" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "querystringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", + "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + } + } + }, + "raw-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-3.1.0.tgz", + "integrity": "sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "schema-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "^2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-package-json": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.0.tgz", + "integrity": "sha512-KLhu8M1ZZNkMcrq1+0UJbR8Dii8KZUqB0Sha4mOx/bknfKI/fyrQVrG/YIt2UOtG667sD8+ee4EXMM91W9dC+A==", + "dev": true, + "requires": { + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "json-parse-better-errors": "^1.0.1", + "normalize-package-data": "^2.0.0", + "slash": "^1.0.0" + } + }, + "read-package-tree": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", + "dev": true, + "requires": { + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0", + "util-promisify": "^2.1.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "parse-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", + "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1", + "lines-and-columns": "^1.1.6" + } + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-5.0.0.tgz", + "integrity": "sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^5.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": 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" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "dev": true, + "requires": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.1.tgz", + "integrity": "sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexpu-core": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.6.0.tgz", + "integrity": "sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.1.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "registry-auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.0.0.tgz", + "integrity": "sha512-lpQkHxd9UL6tb3k/aHAVfnVtn+Bcs9ob5InuFLLEDqSqeq+AljB8GZW9xY0x7F+xYwEcjKe07nyoxzEYz6yvkw==", + "dev": true, + "requires": { + "rc": "^1.2.8", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", + "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "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=", + "dev": true + } + } + }, + "regression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", + "integrity": "sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc=" + }, + "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=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "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=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "resumer": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", + "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", + "requires": { + "through": "~2.3.4" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "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==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rollup": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", + "integrity": "sha1-v2zoO4dRDRY0Ru6qV37WpvxYNeA=", + "requires": { + "chalk": "^1.1.1", + "minimist": "^1.2.0", + "source-map-support": "^0.3.2" + } + }, + "rollup-plugin-commonjs": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", + "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz", + "integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==", + "dev": true, + "requires": { + "rollup-pluginutils": "^2.5.0" + } + }, + "rollup-plugin-node-resolve": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", + "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", + "dev": true, + "requires": { + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.11.1", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-sourcemaps": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.4.2.tgz", + "integrity": "sha1-YhJaqUCHqt97g+9N+vYptHMTXoc=", + "dev": true, + "requires": { + "rollup-pluginutils": "^2.0.1", + "source-map-resolve": "^0.5.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, + "rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "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==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "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==" + }, + "sass": { + "version": "1.22.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.9.tgz", + "integrity": "sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ==", + "dev": true, + "requires": { + "chokidar": ">=2.0.0 <4.0.0" + } + }, + "sass-loader": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.2.0.tgz", + "integrity": "sha512-h8yUWaWtsbuIiOCgR9fd9c2lRXZ2uG+h8Dzg/AGNj+Hg/3TO8+BBAW9mEP+mh8ei+qBKqSJ0F1FLlYjNBc61OA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.0.1", + "neo-async": "^2.5.0", + "pify": "^4.0.1", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "saucelabs": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", + "dev": true, + "requires": { + "https-proxy-agent": "^2.2.1" + } + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + } + } + }, + "selfsigned": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", + "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "dev": true, + "requires": { + "node-forge": "0.9.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "^5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "semver-intersect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz", + "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==", + "dev": true, + "requires": { + "semver": "^5.0.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "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.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "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==", + "dev": true, + "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=", + "dev": true + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "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==", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "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==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "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==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "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=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "simple-git": { + "version": "1.126.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.126.0.tgz", + "integrity": "sha512-47mqHxgZnN8XRa9HbpWprzUv3Ooqz9RY/LSZgvA7jCkW8jcwLahMz7LKugY91KZehfG0sCVPtgXiU72hd6b1Bw==", + "dev": true, + "requires": { + "debug": "^4.0.1" + } + }, + "simple-statistics": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-6.1.1.tgz", + "integrity": "sha512-zGwn0DDRa9Zel4H4n2pjTFIyGoAGpnpjrGIctreCxj5XWrcx9v7Xy7270FkC967WMmcvuc8ZU7m0ZG+hGN7gAA==" + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "smart-buffer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", + "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "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==", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "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==", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "kind-of": "^6.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==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "requires": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "^0.10.0", + "uuid": "^3.0.1" + } + }, + "sockjs-client": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz", + "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==", + "dev": true, + "requires": { + "debug": "^3.2.5", + "eventsource": "^1.0.7", + "faye-websocket": "~0.11.1", + "inherits": "^2.0.3", + "json3": "^3.3.2", + "url-parse": "^1.4.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "socks": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz", + "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "4.0.2" + } + }, + "socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "requires": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "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==", + "dev": true + }, + "source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-loader": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.4.tgz", + "integrity": "sha512-OU6UJUty+i2JDpTItnizPrlpOIBLmQbWMuBg9q5bVtnHACqw1tn9nNwqJLbv0/00JjnJb/Ee5g5WS5vrRv7zIQ==", + "dev": true, + "requires": { + "async": "^2.5.0", + "loader-utils": "^1.1.0" + } + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", + "integrity": "sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8=", + "requires": { + "source-map": "0.1.32" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sourcemap-codec": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", + "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "spdy": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.1.tgz", + "integrity": "sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "speed-measure-webpack-plugin": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.1.tgz", + "integrity": "sha512-qVIkJvbtS9j/UeZumbdfz0vg+QfG/zxonAjzefZrqzkr7xOncLVXkeGbTpzd1gjCBM4PmVNkWlkeTVhgskAGSQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "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==", + "dev": true, + "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=", + "dev": true + }, + "ssf": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.2.tgz", + "integrity": "sha512-rDhAPm9WyIsY8eZEKyE8Qsotb3j/wBdvMWBUsOhJdfhKGLfQidRjiBUV0y/MkyCLiXQ38FG6LWW/VYUtqlIDZQ==", + "requires": { + "frac": "~1.1.2" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "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.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "staged-git-files": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", + "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "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=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "streamroller": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "dev": true, + "requires": { + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.14" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", + "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.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=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string.prototype.trim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", + "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.0", + "function-bind": "^1.0.2" + } + }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "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==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.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" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "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=", + "dev": true + }, + "style-loader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.0.0.tgz", + "integrity": "sha512-B0dOCFwv7/eY31a5PCieNwMgMhVGFe9w+rh7s/Bx8kfFkrth9zfTZquoYvdw8URgiqxObQKcpW51Ugz1HjfdZw==", + "dev": true, + "requires": { + "loader-utils": "^1.2.3", + "schema-utils": "^2.0.1" + }, + "dependencies": { + "schema-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.5.0.tgz", + "integrity": "sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, + "stylus": { + "version": "0.54.5", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", + "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", + "dev": true, + "requires": { + "css-parse": "1.7.x", + "debug": "*", + "glob": "7.0.x", + "mkdirp": "0.5.x", + "sax": "0.5.x", + "source-map": "0.1.x" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "stylus-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz", + "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "lodash.clonedeep": "^4.5.0", + "when": "~3.6.x" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, + "synchronous-promise": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.10.tgz", + "integrity": "sha512-6PC+JRGmNjiG3kJ56ZMNWDPL8hjyghF5cMXIFOKg+NiwwEZZIvxTWd0pinWKyD227odg9ygF8xVhhz7gb8Uq7A==", + "dev": true + }, + "systemjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-5.0.0.tgz", + "integrity": "sha512-hnD/IMQhH0UmawiIGlYVnkCPUbbO/WDQjOC+Q4PewHBdsagI1OHH1re1sg1AYFqq7p9ps6b1Bsx4xCeoeIZSCw==" + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "tape": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/tape/-/tape-4.11.0.tgz", + "integrity": "sha512-yixvDMX7q7JIs/omJSzSZrqulOV51EC9dK8dM0TzImTIkHWfe2/kFyL5v+d9C+SrCMaICk59ujsqFAVidDqDaA==", + "requires": { + "deep-equal": "~1.0.1", + "defined": "~1.0.0", + "for-each": "~0.3.3", + "function-bind": "~1.1.1", + "glob": "~7.1.4", + "has": "~1.0.3", + "inherits": "~2.0.4", + "minimist": "~1.2.0", + "object-inspect": "~1.6.0", + "resolve": "~1.11.1", + "resumer": "~0.0.0", + "string.prototype.trim": "~1.1.2", + "through": "~2.3.8" + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "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" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "terser": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.3.8.tgz", + "integrity": "sha512-otmIRlRVmLChAWsnSFNO0Bfk6YySuBp6G9qrHiJwlLDd4mxe2ta4sjI7TzIR+W1nBMjilzrMcPOz9pSusgx3hQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", + "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.7.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "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==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^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==", + "dev": true + } + } + }, + "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==", + "dev": true, + "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==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tinycolor2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz", + "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "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=", + "dev": true + }, + "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=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "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": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "topojson-client": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.0.1.tgz", + "integrity": "sha512-rfGGzyqefpxOaxvV9OTF9t+1g+WhjGEbAIuCcmKYrQkxr0nttjMMyzZsK+NhLW4cTl2g1bz2jQczPUtEshpbVQ==", + "requires": { + "commander": "2" + } + }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "tree-kill": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.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==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "tsickle": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.37.0.tgz", + "integrity": "sha512-ufUZqLUNqh+kOfr52N/hJ5JbiDO32/CO7ZCteZBX9HA2kiejwEgDaJeJe1GAj2TIu683IgTA/LPKvlns6Liw0w==", + "dev": true, + "requires": { + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==" + }, + "tslint": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.15.0.tgz", + "integrity": "sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA==", + "dev": true, + "requires": { + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.13.0", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "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=", + "dev": true + }, + "type-fest": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", + "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "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=", + "dev": true + }, + "typescript": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "requires": { + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "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==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "universal-analytics": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.20.tgz", + "integrity": "sha512-gE91dtMvNkjO+kWsPstHRtSwHXz0l2axqptGYp5ceg4MsuurloM0PU3pdOfpb5zBXUvyjT4PwhWK2m39uczZuw==", + "dev": true, + "requires": { + "debug": "^3.0.0", + "request": "^2.88.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true, + "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=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "update-notifier": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-3.0.1.tgz", + "integrity": "sha512-grrmrB6Zb8DUiyDIaeRTBCkgISYUgETNe7NglEbVsrLWXeESnlCSP50WfRSj/GmzMPl6Uchj24S/p80nP/ZQrQ==", + "dev": true, + "requires": { + "boxen": "^3.0.0", + "chalk": "^2.0.1", + "configstore": "^4.0.0", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.1.0", + "is-npm": "^3.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "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=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "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=", + "dev": true + } + } + }, + "url-parse": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + }, + "dependencies": { + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "dev": true, + "requires": { + "lru-cache": "4.1.x", + "tmp": "0.0.x" + }, + "dependencies": { + "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==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util-promisify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "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==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "venn.js": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/venn.js/-/venn.js-0.2.20.tgz", + "integrity": "sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==", + "requires": { + "d3-selection": "^1.0.2", + "d3-transition": "^1.0.1", + "fmin": "0.0.2" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vm-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": 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==", + "dev": 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" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "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=", + "dev": 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.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "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=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webdriver-js-extender": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", + "dev": true, + "requires": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + } + }, + "webpack": { + "version": "4.39.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.2.tgz", + "integrity": "sha512-AKgTfz3xPSsEibH00JfZ9sHXGUwIQ6eZ9tLN8+VLzachk1Cw2LVmy+4R7ZiwTa9cZZ15tzySjeMui/UnSCAZhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + } + }, + "webpack-core": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz", + "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", + "dev": true, + "requires": { + "source-list-map": "~0.1.7", + "source-map": "~0.4.1" + }, + "dependencies": { + "source-list-map": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", + "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz", + "integrity": "sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.2", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true + } + } + }, + "webpack-dev-server": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.0.tgz", + "integrity": "sha512-Hs8K9yI6pyMvGkaPTeTonhD6JXVsigXDApYk9JLW4M7viVBspQvb1WdAcWxqtmttxNW4zf2UFLsLNe0y87pIGQ==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "bonjour": "^3.5.0", + "chokidar": "^2.1.6", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.2.1", + "http-proxy-middleware": "^0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.0", + "killable": "^1.0.1", + "loglevel": "^1.6.3", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.21", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.4", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.3.0", + "spdy": "^4.0.1", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.0", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "12.0.5" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": 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==", + "dev": 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" + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "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=", + "dev": 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.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": 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, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": 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.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "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=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.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=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.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": "^11.1.1" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + }, + "webpack-merge": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.1.tgz", + "integrity": "sha512-4p8WQyS98bUJcCvFMbdGZyZmsKuWjWVnVHnAS3FFg0HDaRVrPbkivx2RYCre8UiemD67RsiFFLfn4JhLAin8Vw==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "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==", + "dev": true + } + } + }, + "webpack-subresource-integrity": { + "version": "1.1.0-rc.6", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.6.tgz", + "integrity": "sha512-Az7y8xTniNhaA0620AV1KPwWOqawurVVDzQSpPAeR5RwNbL91GoBSJAAo9cfd+GiFHwsS5bbHepBw1e6Hzxy4w==", + "dev": true, + "requires": { + "webpack-core": "^0.6.8" + } + }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" + }, + "wolfy87-eventemitter": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz", + "integrity": "sha1-NcGsDdGsDBXjXZgVCPwiCEoToBE=" + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" + }, + "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==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "worker-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-3.2.0.tgz", + "integrity": "sha512-W5nRkw7+HlbsEt3qRP6MczwDDISjiRj2GYt9+bpe8A2La00TmJdwzG5bpdMXhRt1qcWmwAvl1TiKaHRa+XDS9Q==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "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=", + "dev": true, + "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=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "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==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xlsx": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.14.5.tgz", + "integrity": "sha512-s/5f4/mjeWREmIWZ+HtDfh/rnz51ar+dZ4LWKZU3u9VBx2zLdSIWTdXgoa52/pnZ9Oe/Vu1W1qzcKzLVe+lq4w==", + "requires": { + "adler-32": "~1.2.0", + "cfb": "^1.1.2", + "codepage": "~1.14.0", + "commander": "~2.17.1", + "crc-32": "~1.2.0", + "exit-on-epipe": "~1.0.1", + "ssf": "~0.10.2" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + } + } + }, + "xml2js": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" + }, + "dependencies": { + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + } + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "^0.2.2" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "yup": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.27.0.tgz", + "integrity": "sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.0.0", + "fn-name": "~2.0.1", + "lodash": "^4.17.11", + "property-expr": "^1.5.0", + "synchronous-promise": "^2.0.6", + "toposort": "^2.0.2" + } + }, + "zone.js": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.9.1.tgz", + "integrity": "sha512-GkPiJL8jifSrKReKaTZ5jkhrMEgXbXYC+IPo1iquBjayRa0q86w3Dipjn8b415jpitMExe9lV8iTsv8tk3DGag==" + } + } +} diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json new file mode 100644 index 00000000000..ae96fe7f87b --- /dev/null +++ b/zeppelin-web-angular/package.json @@ -0,0 +1,96 @@ +{ + "name": "zeppelin", + "version": "0.0.0", + "scripts": { + "postinstall": "npm run build:projects", + "ng": "./node_modules/.bin/ng", + "start": "ng serve --proxy-config proxy.conf.js --extra-webpack-config webpack.partial.js", + "build": "ng build --prod --extra-webpack-config webpack.partial.js", + "build:projects": "npm run build-project:sdk && npm run build-project:vis && npm run build-project:helium", + "build-helium-vis-example": " ng build --project helium-vis-example", + "build-project:sdk": " ng build --project zeppelin-sdk", + "build-project:vis": " ng build --project zeppelin-visualization", + "build-project:helium": "ng build --project zeppelin-helium", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "~8.2.10", + "@angular/cdk": "~8.2.3", + "@angular/common": "~8.2.10", + "@angular/compiler": "~8.2.10", + "@angular/core": "~8.2.10", + "@angular/forms": "~8.2.10", + "@angular/platform-browser": "~8.2.10", + "@angular/platform-browser-dynamic": "~8.2.10", + "@angular/router": "~8.2.10", + "@antv/data-set": "^0.10.2", + "@antv/g2": "^3.5.4", + "ansi-to-html": "^0.6.11", + "core-js": "^2.5.4", + "date-fns": "^1.30.1", + "diff-match-patch": "^1.0.4", + "highlight.js": "^9.15.8", + "lodash": "^4.17.11", + "mathjax": "2.7.5", + "monaco-editor": "^0.18.1", + "ng-zorro-antd": "^8.4.0", + "rxjs": "~6.5.3", + "systemjs": "^5.0.0", + "tslib": "^1.9.0", + "xlsx": "^0.14.3", + "zone.js": "~0.9.1" + }, + "devDependencies": { + "monaco-editor-webpack-plugin": "^1.7.0", + "ngx-build-plus": "^8.1.5", + "@angular-devkit/build-angular": "^0.803.9", + "@angular-devkit/build-ng-packagr": "~0.803.6", + "@angular/cli": "~8.3.9", + "@angular/compiler-cli": "~8.2.10", + "@angular/language-service": "~8.2.10", + "@types/date-fns": "^2.6.0", + "@types/highlight.js": "^9.12.3", + "@types/jasmine": "~3.3.8", + "@types/jasminewd2": "~2.0.3", + "@types/lodash": "^4.14.124", + "@types/mathjax": "^0.0.35", + "@types/node": "~8.9.4", + "codelyzer": "^5.0.0", + "dotenv": "^8.0.0", + "https-proxy-agent": "^2.2.1", + "husky": "^2.2.0", + "jasmine-core": "~3.4.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~4.1.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~2.0.1", + "karma-jasmine-html-reporter": "^1.4.0", + "lint-staged": "^8.1.6", + "ng-packagr": "^5.4.0", + "prettier": "^1.17.0", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tsickle": "^0.37.0", + "tslint": "~5.15.0", + "typescript": "~3.5.3" + }, + "lint-staged": { + "src/**/*.{ts,js,json}": [ + "./node_modules/.bin/prettier --write", + "git add" + ], + "src/**/*.ts": [ + "tslint --project src/tslint.json --fix", + "git add" + ] + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + } +} diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml new file mode 100644 index 00000000000..e0a1f7b3e84 --- /dev/null +++ b/zeppelin-web-angular/pom.xml @@ -0,0 +1,174 @@ + + + + + 4.0.0 + + + zeppelin + org.apache.zeppelin + 0.9.0-SNAPSHOT + .. + + + org.apache.zeppelin + zeppelin-web-angular + war + 0.9.0-SNAPSHOT + Zeppelin: web Application + + + + 3.1.0 + + + + true + false + ../bin + UTF-8 + + + https://nodejs.org/dist/ + https://registry.npmjs.org/npm/-/ + + + + + + + org.apache.maven.plugins + maven-war-plugin + + dist\zeppelin + dist\zeppelin\WEB-INF\web.xml + + + + + com.github.eirslett + frontend-maven-plugin + ${plugin.frontend.version} + + ${plugin.frontend.nodeDownloadRoot} + ${plugin.frontend.npmDownloadRoot} + + + + + install node + + install-node-and-npm + + + ${node.version} + ${npm.version} + + + + + npm install + + npm + + + ${web.e2e.enabled} + install --no-lockfile + + + + + npm build + + npm + + + ${web.e2e.enabled} + run build + + + + + npm test + + npm + + test + + ${web.e2e.disabled} + run test + + + + + npm e2e + + npm + + integration-test + + ${web.e2e.disabled} + run e2e + + + + + + + + + org.codehaus.mojo + cobertura-maven-plugin + + + cobertura + none + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + + + + maven-clean-plugin + + + + node + + + node_modules + + + + + + + maven-resources-plugin + ${plugin.resource.version} + + + + + diff --git a/zeppelin-web-angular/projects/helium-vis-example/README.md b/zeppelin-web-angular/projects/helium-vis-example/README.md new file mode 100644 index 00000000000..e1850116b2e --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/README.md @@ -0,0 +1,36 @@ + + +# HeliumVisExample + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.9. + +## Code scaffolding + +Run `ng generate component component-name --project helium-vis-example` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project helium-vis-example`. +> Note: Don't forget to add `--project helium-vis-example` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build helium-vis-example` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build helium-vis-example`, go to the dist folder `cd dist/helium-vis-example` and run `npm publish`. + +## Running unit tests + +Run `ng test helium-vis-example` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/helium-vis-example/karma.conf.js b/zeppelin-web-angular/projects/helium-vis-example/karma.conf.js new file mode 100644 index 00000000000..ed77432da6e --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/karma.conf.js @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/helium-vis-example'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/helium-vis-example/ng-package.json b/zeppelin-web-angular/projects/helium-vis-example/ng-package.json new file mode 100644 index 00000000000..2193ef3df33 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/helium-vis-example", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/helium-vis-example/package.json b/zeppelin-web-angular/projects/helium-vis-example/package.json new file mode 100644 index 00000000000..17f7cb02fbc --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/package.json @@ -0,0 +1,8 @@ +{ + "name": "helium-vis-example", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^8.2.9", + "@angular/core": "^8.2.9" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts new file mode 100644 index 00000000000..12234517668 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.component.ts @@ -0,0 +1,43 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core'; +import { TableData, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +@Component({ + selector: 'lib-helium-vis-example', + template: ` +
{{tableData | json}}
+ `, + styles: [` + pre { + background: #fff7e7; + padding: 10px; + border: 1px solid #ffd278; + color: #fa7e14; + border-radius: 3px; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JsonVisComponent implements OnInit { + tableData: TableData; + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) {} + + ngOnInit() { + } + + render(): void { + this.tableData = this.visualization.transformed; + } + +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts new file mode 100644 index 00000000000..2578f26df39 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/json-vis.module.ts @@ -0,0 +1,23 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { JsonVisComponent } from './json-vis.component'; +import { CommonModule } from '@angular/common'; + +@NgModule({ + imports: [CommonModule], + declarations: [JsonVisComponent], + entryComponents: [JsonVisComponent], + exports: [JsonVisComponent] +}) +export class JsonVisModule { } diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts b/zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts new file mode 100644 index 00000000000..9f97db4598f --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/json-visualization.ts @@ -0,0 +1,64 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ComponentFactoryResolver, ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { + TableTransformation, + Transformation, + Visualization, + VisualizationComponentPortal +} from '@zeppelin/visualization'; + +import { JsonVisComponent } from './json-vis.component'; + +export class JsonVisualization extends Visualization { + tableTransformation = new TableTransformation(this.getConfig()); + componentPortal = new VisualizationComponentPortal( + this, + JsonVisComponent, + this.portalOutlet, + this.viewContainerRef, + this.componentFactoryResolver + ); + constructor(config: GraphConfig, + private portalOutlet: CdkPortalOutlet, + private viewContainerRef: ViewContainerRef, + private componentFactoryResolver?: ComponentFactoryResolver) { + super(config); + } + + destroy(): void { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + } + + getTransformation(): Transformation { + return this.tableTransformation; + } + + refresh(): void {} + + render(data): void { + this.transformed = data; + if (!this.componentRef) { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + this.componentRef.instance.render(); + } +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts b/zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts new file mode 100644 index 00000000000..82ba8d0ce42 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/public-api.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +/* + * Public API Surface of helium-vis-example + */ + +import { createHeliumPackage, HeliumPackageType } from '@zeppelin/helium'; +import { JsonVisComponent } from './json-vis.component'; +import { JsonVisModule } from './json-vis.module'; +import { JsonVisualization } from './json-visualization'; + +export default createHeliumPackage({ + name: 'helium-vis-example', + id: 'heliumVisExample', + icon: 'appstore', + type: HeliumPackageType.Visualization, + module: JsonVisModule, + component: JsonVisComponent, + visualization: JsonVisualization +}); diff --git a/zeppelin-web-angular/projects/helium-vis-example/src/test.ts b/zeppelin-web-angular/projects/helium-vis-example/src/test.ts new file mode 100644 index 00000000000..9be59f628dd --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/src/test.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone'; +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json new file mode 100644 index 00000000000..bd23948e591 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.lib.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/helium-vis-example/tslint.json b/zeppelin-web-angular/projects/helium-vis-example/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/helium-vis-example/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/README.md b/zeppelin-web-angular/projects/zeppelin-helium/README.md new file mode 100644 index 00000000000..16ea0ea2bd6 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/README.md @@ -0,0 +1,36 @@ + + +# ZeppelinHelium + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.8. + +## Code scaffolding + +Run `ng generate component component-name --project zeppelin-helium` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project zeppelin-helium`. +> Note: Don't forget to add `--project zeppelin-helium` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build zeppelin-helium` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build zeppelin-helium`, go to the dist folder `cd dist/zeppelin-helium` and run `npm publish`. + +## Running unit tests + +Run `ng test zeppelin-helium` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js b/zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js new file mode 100644 index 00000000000..3ddb74a1a49 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/karma.conf.js @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/zeppelin-helium'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/ng-package.json b/zeppelin-web-angular/projects/zeppelin-helium/ng-package.json new file mode 100644 index 00000000000..da717624c15 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/zeppelin-helium", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-helium/package.json b/zeppelin-web-angular/projects/zeppelin-helium/package.json new file mode 100644 index 00000000000..cd0b499afa9 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/package.json @@ -0,0 +1,12 @@ +{ + "name": "@zeppelin/helium", + "version": "0.0.0", + "peerDependencies": { + "@angular/common": "~8.2.8", + "@angular/core": "~8.2.8", + "@angular/forms": "~8.2.7", + "@angular/router": "~8.2.7", + "rxjs": "~6.5.3", + "ng-zorro-antd": "^8.3.0" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts new file mode 100644 index 00000000000..677b3d7d1cf --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts @@ -0,0 +1,43 @@ +/* + * 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 * as common from '@angular/common'; +import * as core from '@angular/core'; +import * as forms from '@angular/forms'; +import * as router from '@angular/router'; +import * as rxjs from 'rxjs'; + +import * as dataSet from '@antv/data-set'; +import * as g2 from '@antv/g2'; +import * as sdk from '@zeppelin/sdk'; +import * as visualization from '@zeppelin/visualization'; +import * as lodash from 'lodash'; + +import * as ngZorro from 'ng-zorro-antd'; +import * as tslib from 'tslib'; +import * as zeppelinHelium from './public-api'; + +export const COMMON_DEPS = { + '@angular/core': core, + '@angular/common': common, + '@angular/forms': forms, + '@angular/router': router, + '@antv/data-set': dataSet, + '@antv/g2': g2, + '@zeppelin/sdk': sdk, + '@zeppelin/visualization': visualization, + '@zeppelin/helium': zeppelinHelium, + 'lodash': lodash, + 'ng-zorro-antd': ngZorro, + rxjs, + tslib +}; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/index.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts new file mode 100644 index 00000000000..4b9b89fd7db --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/public-api.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +/* + * Public API Surface of zeppelin-helium + */ + +export * from './zeppelin-helium.service'; +export * from './zeppelin-helium.module'; diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/test.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/test.ts new file mode 100644 index 00000000000..9be59f628dd --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/test.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/dist/zone'; +import 'zone.js/dist/zone-testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts new file mode 100644 index 00000000000..e24ac800a78 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.module.ts @@ -0,0 +1,16 @@ +/* + * 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 { NgModule } from '@angular/core'; + +@NgModule({}) +export class ZeppelinHeliumModule { } diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts new file mode 100644 index 00000000000..10f8997dbf7 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/src/zeppelin-helium.service.ts @@ -0,0 +1,96 @@ +/* + * 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 { Injectable, Type } from '@angular/core'; +import { Visualization } from '@zeppelin/visualization'; +import { COMMON_DEPS } from './common-deps'; +import { ZeppelinHeliumModule } from './zeppelin-helium.module'; + +// tslint:disable-next-line:no-any +const SystemJs = (window as any).System; + +// tslint:disable-next-line:no-any +export class ZeppelinHeliumPackage { + constructor( + public name: string, + public id: string, + // tslint:disable-next-line:no-any + public module: Type, + // tslint:disable-next-line:no-any + public component: Type, + // tslint:disable-next-line:no-any + public visualization?: any, + public icon = 'build' + ) { + } +} + +export enum HeliumPackageType { + Visualization +} + +// tslint:disable-next-line:no-any +export function createHeliumPackage(config: { + name: string; + id: string; + icon?: string; + type: HeliumPackageType; + // tslint:disable-next-line:no-any + module: Type; + // tslint:disable-next-line:no-any + component: Type; + // tslint:disable-next-line:no-any + visualization?: any +}) { + return new ZeppelinHeliumPackage( + config.name, + config.id, + config.module, + config.component, + config.visualization, + config.icon + ); +} + +@Injectable({ + providedIn: ZeppelinHeliumModule +}) +export class ZeppelinHeliumService { + + depsDefined = false; + + constructor() { } + + defineDeps() { + if (this.depsDefined) { + return; + } + Object.keys(COMMON_DEPS).forEach(externalKey => + // tslint:disable-next-line:no-any + (window as any).define(externalKey, [], () => COMMON_DEPS[ externalKey ]) + ); + this.depsDefined = true; + } + + loadPackage(name: string): Promise { + this.defineDeps(); + return SystemJs.import(`./assets/helium-packages/${name}.umd.js`) + .then(() => SystemJs.import(name)) + .then(plugin => { + if (plugin instanceof ZeppelinHeliumPackage) { + return Promise.resolve(plugin); + } else { + throw new TypeError('This module is not a valid helium package'); + } + }); + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json new file mode 100644 index 00000000000..45b781973db --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "flatModuleId": "@zeppelin/helium" + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-helium/tslint.json b/zeppelin-web-angular/projects/zeppelin-helium/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-helium/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/README.md b/zeppelin-web-angular/projects/zeppelin-sdk/README.md new file mode 100644 index 00000000000..91a87204e35 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/README.md @@ -0,0 +1,36 @@ + + +# ZeppelinSdk + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.9. + +## Code scaffolding + +Run `ng generate component component-name --project zeppelin-sdk` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project zeppelin-sdk`. +> Note: Don't forget to add `--project zeppelin-sdk` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build zeppelin-sdk` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build zeppelin-sdk`, go to the dist folder `cd dist/zeppelin-sdk` and run `npm publish`. + +## Running unit tests + +Run `ng test zeppelin-sdk` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js b/zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js new file mode 100644 index 00000000000..bf69ea2ebb1 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/karma.conf.js @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/zeppelin-sdk'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json b/zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json new file mode 100644 index 00000000000..41dc5a032d3 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/zeppelin-sdk", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/package.json b/zeppelin-web-angular/projects/zeppelin-sdk/package.json new file mode 100644 index 00000000000..9be3b66d006 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/package.json @@ -0,0 +1,8 @@ +{ + "name": "@zeppelin/sdk", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^8.2.9", + "@angular/core": "^8.2.9" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts new file mode 100644 index 00000000000..0a5ad6dadd5 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts @@ -0,0 +1,129 @@ +/* + * 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. + */ + +export type EditorMode = + | 'ace/mode/scala' + | 'ace/mode/python' + | 'ace/mode/r' + | 'ace/mode/sql' + | 'ace/mode/markdown' + | 'ace/mode/sh'; + +export type EditorCompletionKey = 'TAB' | string; +export type EditorLanguage = 'scala' | 'python' | 'r' | 'sql' | 'markdown' | 'sh' | string; + +export interface Ticket { + principal: string; + ticket: string; + redirectURL?: string; + roles: string; +} + +export interface ConfigurationsInfo { + configurations: { + 'zeppelin.war.tempdir': string; + 'zeppelin.notebook.azure.user': string; + 'zeppelin.helium.npm.installer.url': string; + 'zeppelin.notebook.git.remote.username': string; + 'zeppelin.interpreter.remoterunner': string; + 'zeppelin.notebook.s3.user': string; + 'zeppelin.server.port': string; + 'zeppelin.plugins.dir': string; + 'zeppelin.notebook.new_format.delete_old': string; + 'zeppelin.ssl.truststore.type': string; + 'zeppelin.ssl.keystore.path': string; + 'zeppelin.notebook.s3.bucket': string; + 'zeppelin.notebook.git.remote.access-token': string; + 'zeppelin.recovery.dir': string; + 'zeppelin.notebook.s3.timeout': string; + 'zeppelin.notebook.cron.enable': string; + 'zeppelin.server.addr': string; + 'zeppelin.username.force.lowercase': string; + 'zeppelin.ssl.keystore.type': string; + 'zeppelin.ssl.truststore.path': string; + 'zeppelin.notebook.dir': string; + 'zeppelin.interpreter.lifecyclemanager.class': string; + 'zeppelin.notebook.gcs.dir': string; + 'zeppelin.notebook.s3.sse': string; + 'zeppelin.websocket.max.text.message.size': string; + 'zeppelin.notebook.git.remote.origin': string; + 'zeppelin.server.authorization.header.clear': string; + isRevisionSupported: string; + 'zeppelin.interpreter.dep.mvnRepo': string; + 'zeppelin.ssl': string; + 'zeppelin.notebook.autoInterpreterBinding': string; + 'zeppelin.config.storage.class': string; + 'zeppelin.helium.node.installer.url': string; + 'zeppelin.cluster.heartbeat.interval': string; + 'zeppelin.notebook.storage': string; + 'zeppelin.notebook.new_format.convert': string; + 'zeppelin.interpreter.dir': string; + 'zeppelin.anonymous.allowed': string; + 'zeppelin.credentials.persist': string; + 'zeppelin.notebook.mongo.uri': string; + 'zeppelin.config.fs.dir': string; + 'zeppelin.server.allowed.origins': string; + 'zeppelin.notebook.mongo.database': string; + 'zeppelin.encoding': string; + 'zeppelin.server.jetty.request.header.size': string; + 'zeppelin.search.temp.path': string; + 'zeppelin.cluster.heartbeat.timeout': string; + 'zeppelin.notebook.s3.endpoint': string; + 'zeppelin.notebook.homescreen.hide': string; + 'zeppelin.scheduler.threadpool.size': string; + 'zeppelin.notebook.azure.share': string; + 'zeppelin.helium.yarnpkg.installer.url': string; + 'zeppelin.server.strict.transport': string; + 'zeppelin.interpreter.setting': string; + 'zeppelin.server.xxss.protection': string; + 'zeppelin.server.rpc.portRange': string; + 'zeppelin.war': string; + 'zeppelin.interpreter.output.limit': string; + 'zeppelin.dep.localrepo': string; + 'zeppelin.interpreter.max.poolsize': string; + 'zeppelin.server.ssl.port': string; + 'zeppelin.notebook.mongo.collection': string; + 'zeppelin.notebook.public': string; + 'zeppelin.helium.registry': string; + 'zeppelin.server.kerberos.principal': string; + 'zeppelin.server.default.dir.allowed': string; + 'zeppelin.ssl.client.auth': string; + 'zeppelin.server.context.path': string; + 'zeppelin.recovery.storage.class': string; + 'zeppelin.notebook.default.owner.username': string; + 'zeppelin.home': string; + 'zeppelin.interpreter.lifecyclemanager.timeout.threshold': string; + 'zeppelin.cluster.addr': string; + 'zeppelin.notebook.git.remote.url': string; + 'zeppelin.notebook.mongo.autoimport': string; + 'zeppelin.notebook.one.way.sync': string; + 'zeppelin.notebook.homescreen': string; + 'zeppelin.interpreter.connect.timeout': string; + 'zeppelin.server.xframe.options': string; + 'zeppelin.interpreter.lifecyclemanager.timeout.checkinterval': string; + 'zeppelin.server.kerberos.keytab': string; + 'zeppelin.interpreter.rpc.portRange': string; + 'zeppelin.interpreter.group.default': string; + 'zeppelin.conf.dir': string; + 'zeppelin.interpreter.localRepo': string; + 'zeppelin.notebook.collaborative.mode.enable': string; + 'zeppelin.search.use.disk': string; + }; +} + +export interface ErrorInfo { + info?: string; +} + +export interface AuthInfo { + info?: string; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts new file mode 100644 index 00000000000..ddf934e2433 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts @@ -0,0 +1,164 @@ +/* + * 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 { AuthInfo, ConfigurationsInfo, ErrorInfo } from './message-common.interface'; +import { + CheckpointNote, + CloneNote, + CollaborativeModeStatus, + DeleteNote, + EditorSettingReceived, + EditorSettingSend, + FolderRename, + GetInterpreterBindings, + GetNode, + ListRevision, + ListRevisionHistory, + MoveFolderToTrash, + MoveNoteToTrash, + NewNote, + Note, + NotesInfo, + NoteRename, + NoteRevision, + NoteRevisionForCompare, + NoteRunningStatus, + NoteUpdate, + NoteUpdated, + ParagraphAdded, + ParagraphMoved, + RemoveFolder, + RemoveNoteForms, + RestoreFolder, + RestoreNote, + SaveNoteFormsReceived, + SaveNoteFormsSend, + SetNoteRevision, + SetNoteRevisionStatus, + UpdateParagraph, + UpdatePersonalizedMode +} from './message-notebook.interface'; +import { + AngularObjectClientBind, + AngularObjectClientUnbind, + AngularObjectRemove, + AngularObjectUpdate, + AngularObjectUpdated, + CancelParagraph, + CommitParagraph, + Completion, + CompletionReceived, + CopyParagraph, + InsertParagraph, + MoveParagraph, + ParagraphClearAllOutput, + ParagraphClearOutput, + ParagraphRemove, + ParagraphRemoved, + ParasInfo, + PatchParagraphReceived, + PatchParagraphSend, + Progress, + RunAllParagraphs, + RunParagraph +} from './message-paragraph.interface'; + +import { ListNoteJobs, ListUpdateNoteJobs } from './message-job.interface'; + +import { InterpreterBindings, InterpreterSetting } from './message-interpreter.interface'; +import { OP } from './message-operator.interface'; + +export type MixMessageDataTypeMap = MessageSendDataTypeMap & MessageReceiveDataTypeMap; + +export interface MessageReceiveDataTypeMap { + [OP.COMPLETION_LIST]: CompletionReceived; + [OP.NOTES_INFO]: NotesInfo; + [OP.CONFIGURATIONS_INFO]: ConfigurationsInfo; + [OP.NOTE]: Note; + [OP.NOTE_REVISION]: NoteRevision; + [OP.ERROR_INFO]: ErrorInfo; + [OP.LIST_NOTE_JOBS]: ListNoteJobs; + [OP.LIST_UPDATE_NOTE_JOBS]: ListUpdateNoteJobs; + [OP.INTERPRETER_SETTINGS]: InterpreterSetting; + [OP.LIST_REVISION_HISTORY]: ListRevision; + [OP.INTERPRETER_BINDINGS]: InterpreterBindings; + [OP.COLLABORATIVE_MODE_STATUS]: CollaborativeModeStatus; + [OP.SET_NOTE_REVISION]: SetNoteRevisionStatus; + [OP.PARAGRAPH_ADDED]: ParagraphAdded; + [OP.NOTE_RUNNING_STATUS]: NoteRunningStatus; + [OP.NEW_NOTE]: NoteRevision; + [OP.SAVE_NOTE_FORMS]: SaveNoteFormsSend; + [OP.PARAGRAPH]: UpdateParagraph; + [OP.PATCH_PARAGRAPH]: PatchParagraphSend; + [OP.PARAGRAPH_REMOVED]: ParagraphRemoved; + [OP.EDITOR_SETTING]: EditorSettingReceived; + [OP.PROGRESS]: Progress; + [OP.PARAGRAPH_MOVED]: ParagraphMoved; + [OP.AUTH_INFO]: AuthInfo; + [OP.NOTE_UPDATED]: NoteUpdated; + [OP.ANGULAR_OBJECT_UPDATE]: AngularObjectUpdate; + [OP.ANGULAR_OBJECT_REMOVE]: AngularObjectRemove; + [OP.PARAS_INFO]: ParasInfo; +} + +export interface MessageSendDataTypeMap { + [OP.PING]: undefined; + [OP.LIST_CONFIGURATIONS]: undefined; + [OP.LIST_NOTES]: undefined; + [OP.GET_HOME_NOTE]: undefined; + [OP.RESTORE_ALL]: undefined; + [OP.EMPTY_TRASH]: undefined; + [OP.RELOAD_NOTES_FROM_REPO]: undefined; + [OP.GET_NOTE]: GetNode; + [OP.NEW_NOTE]: NewNote; + [OP.MOVE_NOTE_TO_TRASH]: MoveNoteToTrash; + [OP.MOVE_FOLDER_TO_TRASH]: MoveFolderToTrash; + [OP.RESTORE_NOTE]: RestoreNote; + [OP.RESTORE_FOLDER]: RestoreFolder; + [OP.REMOVE_FOLDER]: RemoveFolder; + [OP.DEL_NOTE]: DeleteNote; + [OP.CLONE_NOTE]: CloneNote; + [OP.NOTE_UPDATE]: NoteUpdate; + [OP.UPDATE_PERSONALIZED_MODE]: UpdatePersonalizedMode; + [OP.NOTE_RENAME]: NoteRename; + [OP.FOLDER_RENAME]: FolderRename; + [OP.MOVE_PARAGRAPH]: MoveParagraph; + [OP.INSERT_PARAGRAPH]: InsertParagraph; + [OP.COPY_PARAGRAPH]: CopyParagraph; + [OP.ANGULAR_OBJECT_UPDATED]: AngularObjectUpdated; + [OP.ANGULAR_OBJECT_CLIENT_BIND]: AngularObjectClientBind; + [OP.ANGULAR_OBJECT_CLIENT_UNBIND]: AngularObjectClientUnbind; + [OP.CANCEL_PARAGRAPH]: CancelParagraph; + [OP.PARAGRAPH_EXECUTED_BY_SPELL]: {}; // TODO(hsuanxyz) + [OP.RUN_PARAGRAPH]: RunParagraph; + [OP.RUN_ALL_PARAGRAPHS]: RunAllParagraphs; + [OP.PARAGRAPH_REMOVE]: ParagraphRemove; + [OP.PARAGRAPH_CLEAR_OUTPUT]: ParagraphClearOutput; + [OP.PARAGRAPH_CLEAR_ALL_OUTPUT]: ParagraphClearAllOutput; + [OP.COMPLETION]: Completion; + [OP.COMMIT_PARAGRAPH]: CommitParagraph; + [OP.PATCH_PARAGRAPH]: PatchParagraphReceived; + [OP.IMPORT_NOTE]: {}; // TODO(hsuanxyz) + [OP.CHECKPOINT_NOTE]: CheckpointNote; + [OP.SET_NOTE_REVISION]: SetNoteRevision; + [OP.LIST_REVISION_HISTORY]: ListRevisionHistory; + [OP.NOTE_REVISION]: NoteRevision; + [OP.NOTE_REVISION_FOR_COMPARE]: NoteRevisionForCompare; + [OP.EDITOR_SETTING]: EditorSettingSend; + [OP.LIST_NOTE_JOBS]: undefined; + [OP.UNSUBSCRIBE_UPDATE_NOTE_JOBS]: undefined; + [OP.LIST_UPDATE_NOTE_JOBS]: undefined; + [OP.GET_INTERPRETER_BINDINGS]: GetInterpreterBindings; + [OP.GET_INTERPRETER_SETTINGS]: undefined; + [OP.SAVE_NOTE_FORMS]: SaveNoteFormsReceived; + [OP.REMOVE_NOTE_FORMS]: RemoveNoteForms; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts new file mode 100644 index 00000000000..c59e459410e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-interpreter.interface.ts @@ -0,0 +1,70 @@ +/* + * 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. + */ + +export interface InterpreterSetting { + interpreterSettings: InterpreterItem[]; +} + +export interface InterpreterItem { + id: string; + name: string; + group: string; + properties: Properties; + status: string; + interpreterGroup: InterpreterGroupItem[]; + dependencies: string[]; + option: Option; +} + +export interface InterpreterBindings { + interpreterBindings: InterpreterBindingItem[]; +} + +export interface InterpreterBindingItem { + id: string; + name: string; + selected: boolean; + interpreters: InterpreterGroupItem[]; +} + +interface Properties { + [name: string]: { + name: string; + value: boolean; + type: string; + }; +} + +interface InterpreterGroupItem { + name: string; + class: string; + defaultInterpreter: boolean; + editor?: Editor; +} + +interface Editor { + language?: string; + editOnDblClick?: boolean; + completionKey?: string; + completionSupport?: boolean; +} + +interface Option { + remote: boolean; + port: number; + isExistingProcess: boolean; + setPermission: boolean; + owners: string[]; + isUserImpersonate: boolean; + perNote?: string; + perUser?: string; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts new file mode 100644 index 00000000000..c59122b3a38 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-job.interface.ts @@ -0,0 +1,48 @@ +/* + * 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. + */ + +export interface ListNoteJobs { + noteJobs: NoteJobs; +} + +export interface ListUpdateNoteJobs { + noteRunningJobs: NoteJobs; +} + +export interface NoteJobs { + lastResponseUnixTime: number; + jobs: JobsItem[]; +} +export interface JobsItem { + noteId: string; + noteName: string; + noteType: string; + interpreter: string; + isRunningJob: boolean; + isRemoved: boolean; + unixTimeLastRun: number; + paragraphs: JobItemParagraphItem[]; +} +export interface JobItemParagraphItem { + id: string; + name: string; + status: JobStatus; +} + +export enum JobStatus { + READY = 'READY', + FINISHED = 'FINISHED', + ABORT = 'ABORT', + ERROR = 'ERROR', + PENDING = 'PENDING', + RUNNING = 'RUNNING' +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts new file mode 100644 index 00000000000..f7b22de6daf --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts @@ -0,0 +1,209 @@ +/* + * 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 { ParagraphItem } from './message-paragraph.interface'; + +interface ID { + id: string; +} + +interface Name { + name: string; +} + +export type GetNode = ID; +export type MoveNoteToTrash = ID; +export type MoveFolderToTrash = ID; +export type RestoreNote = ID; +export type RestoreFolder = ID; +export type DeleteNote = ID; +export type RemoveFolder = ID; +export type CloneNote = ID & Name; +export type FolderRename = ID & Name; +export type PersonalizedMode = 'true' | 'false'; + +export interface NoteRename extends Name, ID { + relative: boolean; +} + +export interface SendNote { + id: string; + noteParams: NoteParams; +} + +export interface NoteUpdated { + config: NoteConfig; + info: NoteInfo; + name: string; +} + +export interface Note { + note?: { + paragraphs: ParagraphItem[]; + name: string; + id: string; + defaultInterpreterGroup: string; + noteParams: NoteParams; + noteForms: NoteForms; + angularObjects: NoteAngularObjects; + config: NoteConfig; + info: NoteInfo; + }; +} + +export interface NoteAngularObjects { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface NoteInfo { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface NoteParams { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface NoteForms { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface RemoveNoteForms { + noteId: string; + formName: string; +} + +export interface SaveNoteFormsReceived { + noteId: string; + noteParams: NoteParams; +} + +export interface GetInterpreterBindings { + noteId: string; +} + +export interface EditorSettingSend { + paragraphId: string; + magic: string; +} + +export interface EditorSettingReceived { + paragraphId: string; + editor: { + completionSupport: boolean; + editOnDblClick: boolean; + language: string; + }; +} + +export interface NoteRevisionForCompare { + noteId: string; + revisionId: string; + position: string; +} + +export interface CollaborativeModeStatus { + status: boolean; + users: string[]; +} + +export interface ParagraphMoved { + index: number; + id: string; +} + +export interface UpdateParagraph { + paragraph: ParagraphItem; +} + +export interface SaveNoteFormsSend { + formsData: { + forms: NoteForms; + params: NoteParams; + }; +} + +export interface NoteRunningStatus { + status: boolean; +} + +export interface ParagraphAdded { + index: number; + paragraph: ParagraphItem; +} + +export interface SetNoteRevisionStatus { + status: boolean; +} + +export interface ListRevision { + revisionList: RevisionListItem[]; +} + +export interface RevisionListItem { + id: string; + message: string; + time?: number; +} + +export interface NoteRevision { + note?: Note['note']; + noteId: string; + revisionId: string; +} + +export interface ListRevisionHistory { + noteId: string; +} + +export interface SetNoteRevision { + noteId: string; + revisionId: string; +} + +export interface CheckpointNote { + noteId: string; + commitMessage: string; +} + +export interface NoteUpdate extends Name, ID { + config: NoteConfig; +} + +export interface NewNote extends Name { + defaultInterpreterGroup: string; +} + +export interface NotesInfo { + notes: NotesInfoItem[]; +} + +export interface NotesInfoItem extends ID { + path: string; +} + +export interface NoteConfig { + cron?: string; + releaseresource: boolean; + cronExecutingRoles?: string; + cronExecutingUser?: string; + isZeppelinNotebookCronEnable: boolean; + looknfeel: 'report' | 'default' | 'simple'; + personalizedMode: PersonalizedMode; +} + +export interface UpdatePersonalizedMode extends ID { + personalized: PersonalizedMode; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts new file mode 100644 index 00000000000..d3ce82b6029 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts @@ -0,0 +1,482 @@ +/* + * 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. + */ + +// tslint:disable:no-redundant-jsdoc +/** + * Representation of event type. + */ +export enum OP { + /** + * [c-s] + * load note for home screen + */ + GET_HOME_NOTE = 'GET_HOME_NOTE', + + /** + * [c-s] + * client load note + * @param id note id + */ + GET_NOTE = 'GET_NOTE', + + /** + * [s-c] + * note info + * @param note serialized SendNote object + */ + NOTE = 'NOTE', + + /** + * [s-c] + * paragraph info + * @param paragraph serialized paragraph object + */ + PARAGRAPH = 'PARAGRAPH', + + /** + * [s-c] + * progress update + * @param id paragraph id + * @param progress percentage progress + */ + PROGRESS = 'PROGRESS', + + /** + * [c-s] + * create new notebook + */ + NEW_NOTE = 'NEW_NOTE', + + /** + * [c-s] + * delete notebook + * @param id note id + */ + DEL_NOTE = 'DEL_NOTE', + REMOVE_FOLDER = 'REMOVE_FOLDER', + MOVE_NOTE_TO_TRASH = 'MOVE_NOTE_TO_TRASH', + MOVE_FOLDER_TO_TRASH = 'MOVE_FOLDER_TO_TRASH', + RESTORE_FOLDER = 'RESTORE_FOLDER', + RESTORE_NOTE = 'RESTORE_NOTE', + RESTORE_ALL = 'RESTORE_ALL', + EMPTY_TRASH = 'EMPTY_TRASH', + + /** + * [c-s] + * clone new notebook + * @param id id of note to clone + * @param name name for the cloned note + */ + CLONE_NOTE = 'CLONE_NOTE', + + /** + * [c-s] + * import notebook + * @param object notebook + */ + IMPORT_NOTE = 'IMPORT_NOTE', + NOTE_UPDATE = 'NOTE_UPDATE', + NOTE_RENAME = 'NOTE_RENAME', + + /** + * [c-s] + * update personalized mode (boolean) + * @param note id and boolean personalized mode value + */ + UPDATE_PERSONALIZED_MODE = 'UPDATE_PERSONALIZED_MODE', + FOLDER_RENAME = 'FOLDER_RENAME', + + /** + * [c-s] + * run paragraph + * @param id paragraph id + * @param paragraph paragraph content.ie. script + * @param config paragraph config + * @param params paragraph params + */ + RUN_PARAGRAPH = 'RUN_PARAGRAPH', + + /** + * [c-s] + * commit paragraph + * @param id paragraph id + * @param title paragraph title + * @param paragraph paragraph content.ie. script + * @param config paragraph config + * @param params paragraph params + */ + COMMIT_PARAGRAPH = 'COMMIT_PARAGRAPH', + + /** + * [c-s] + * cancel paragraph run + * @param id paragraph id + */ + CANCEL_PARAGRAPH = 'CANCEL_PARAGRAPH', + + /** + * [c-s] + * move paragraph order + * @param id paragraph id + * @param index index the paragraph want to go + */ + MOVE_PARAGRAPH = 'MOVE_PARAGRAPH', + + /** + * [c-s] + * create new paragraph below current paragraph + * @param target index + */ + INSERT_PARAGRAPH = 'INSERT_PARAGRAPH', + + /** + * [c-s] + * create new para below current para as a copy of current para + * @param target index + * @param title paragraph title + * @param paragraph paragraph content.ie. script + * @param config paragraph config + * @param params paragraph params + */ + COPY_PARAGRAPH = 'COPY_PARAGRAPH', + + /** + * [c-s] + * ask paragraph editor setting + * @param magic magic keyword written in paragraph + * ex) spark.spark or spark + */ + EDITOR_SETTING = 'EDITOR_SETTING', + + /** + * [c-s] + * ask completion candidates + * @param id + * @param buf current code + * @param cursor cursor position in code + */ + COMPLETION = 'COMPLETION', + + /** + * [s-c] + * send back completion candidates list + * @param id + * @param completions list of string + */ + COMPLETION_LIST = 'COMPLETION_LIST', + + /** + * [c-s] + * ask list of note + */ + LIST_NOTES = 'LIST_NOTES', + + /** + * [c-s] + * reload notes from repo + */ + RELOAD_NOTES_FROM_REPO = 'RELOAD_NOTES_FROM_REPO', + + /** + * [s-c] + * list of note infos + * @param notes serialized List object + */ + NOTES_INFO = 'NOTES_INFO', + PARAGRAPH_REMOVE = 'PARAGRAPH_REMOVE', + + /** + * [c-s] + * clear output of paragraph + */ + PARAGRAPH_CLEAR_OUTPUT = 'PARAGRAPH_CLEAR_OUTPUT', + + /** [c-s] + * clear output of all paragraphs + */ + PARAGRAPH_CLEAR_ALL_OUTPUT = 'PARAGRAPH_CLEAR_ALL_OUTPUT', + + /** + * [s-c] + * ppend output + */ + PARAGRAPH_APPEND_OUTPUT = 'PARAGRAPH_APPEND_OUTPUT', + + /** + * [s-c] + * update (replace) output + */ + PARAGRAPH_UPDATE_OUTPUT = 'PARAGRAPH_UPDATE_OUTPUT', + PING = 'PING', + AUTH_INFO = 'AUTH_INFO', + + /** + * [s-c] + * add/update angular object + */ + ANGULAR_OBJECT_UPDATE = 'ANGULAR_OBJECT_UPDATE', + + /** [s-c] + * add angular object del + */ + ANGULAR_OBJECT_REMOVE = 'ANGULAR_OBJECT_REMOVE', + + /** + * [c-s] + * angular object value updated + */ + ANGULAR_OBJECT_UPDATED = 'ANGULAR_OBJECT_UPDATED', + + /** + * [c-s] + * angular object updated from AngularJS z object + */ + ANGULAR_OBJECT_CLIENT_BIND = 'ANGULAR_OBJECT_CLIENT_BIND', + + /** + * [c-s] + * angular object unbind from AngularJS z object + */ + ANGULAR_OBJECT_CLIENT_UNBIND = 'ANGULAR_OBJECT_CLIENT_UNBIND', + + /** + * [c-s] + * ask all key/value pairs of configurations + */ + LIST_CONFIGURATIONS = 'LIST_CONFIGURATIONS', + + /** + * [s-c] + * all key/value pairs of configurations + * @param settings serialized Map object + */ + CONFIGURATIONS_INFO = 'CONFIGURATIONS_INFO', + + /** + * [c-s] + * checkpoint note to storage repository + * @param noteId + * @param checkpointName + */ + CHECKPOINT_NOTE = 'CHECKPOINT_NOTE', + + /** + * [c-s] + * list revision history of the notebook + * @param noteId + */ + LIST_REVISION_HISTORY = 'LIST_REVISION_HISTORY', + + /** + * [c-s] + * get certain revision of note + * @param noteId + * @param revisionId + */ + NOTE_REVISION = 'NOTE_REVISION', + + /** + * [c-s] + * set current notebook head to this revision + * @param noteId + * @param revisionId + */ + SET_NOTE_REVISION = 'SET_NOTE_REVISION', + + /** + * [c-s] + * get certain revision of note for compare + * @param noteId + * @param revisionId + * @param position + */ + NOTE_REVISION_FOR_COMPARE = 'NOTE_REVISION_FOR_COMPARE', + + /** + * [s-c] + * append output + */ + APP_APPEND_OUTPUT = 'APP_APPEND_OUTPUT', + + /** + * [s-c] + * update (replace) output + */ + APP_UPDATE_OUTPUT = 'APP_UPDATE_OUTPUT', + + /** + * [s-c] + * on app load + */ + APP_LOAD = 'APP_LOAD', + + /** + * [s-c] + * on app status change + */ + APP_STATUS_CHANGE = 'APP_STATUS_CHANGE', + + /** + * [s-c] + * get note job management information + */ + LIST_NOTE_JOBS = 'LIST_NOTE_JOBS', + + /** + * [c-s] + * get job management information for until unixtime + */ + LIST_UPDATE_NOTE_JOBS = 'LIST_UPDATE_NOTE_JOBS', + + /** + * [c-s] + * unsubscribe job information for job management + * @param unixTime + */ + UNSUBSCRIBE_UPDATE_NOTE_JOBS = 'UNSUBSCRIBE_UPDATE_NOTE_JOBS', + + /** + * [c-s] + * get interpreter bindings + */ + GET_INTERPRETER_BINDINGS = 'GET_INTERPRETER_BINDINGS', + + /** + * [s-c] + * interpreter bindings + */ + INTERPRETER_BINDINGS = 'INTERPRETER_BINDINGS', + + /** + * [c-s] + * get interpreter settings + */ + GET_INTERPRETER_SETTINGS = 'GET_INTERPRETER_SETTINGS', + + /** + * [s-c] + * interpreter settings + */ + INTERPRETER_SETTINGS = 'INTERPRETER_SETTINGS', + + /** + * [s-c] + * error information to be sent + */ + ERROR_INFO = 'ERROR_INFO', + + /** + * [s-c] + * error information to be sent + */ + SESSION_LOGOUT = 'SESSION_LOGOUT', + + /** + * [s-c] + * Change websocket to watcher mode. + */ + WATCHER = 'WATCHER', + + /** + * [s-c] + * paragraph is added + */ + PARAGRAPH_ADDED = 'PARAGRAPH_ADDED', + + /** + * [s-c] + * paragraph deleted + */ + PARAGRAPH_REMOVED = 'PARAGRAPH_REMOVED', + + /** + * [s-c] + * paragraph moved + */ + PARAGRAPH_MOVED = 'PARAGRAPH_MOVED', + + /** + * [s-c] + * paragraph updated(name, config) + */ + NOTE_UPDATED = 'NOTE_UPDATED', + + /** + * [c-s] + * run all paragraphs + */ + RUN_ALL_PARAGRAPHS = 'RUN_ALL_PARAGRAPHS', + + /** + * [c-s] + * paragraph was executed by spell + */ + PARAGRAPH_EXECUTED_BY_SPELL = 'PARAGRAPH_EXECUTED_BY_SPELL', + + /** + * [s-c] + * run paragraph using spell + */ + RUN_PARAGRAPH_USING_SPELL = 'RUN_PARAGRAPH_USING_SPELL', + + /** + * [s-c] + * paragraph runtime infos + */ + PARAS_INFO = 'PARAS_INFO', + + /** + * save note forms + */ + SAVE_NOTE_FORMS = 'SAVE_NOTE_FORMS', + + /** + * remove note forms + */ + REMOVE_NOTE_FORMS = 'REMOVE_NOTE_FORMS', + + /** + * [s-c] + * start to download an interpreter + */ + INTERPRETER_INSTALL_STARTED = 'INTERPRETER_INSTALL_STARTED', + + /** + * [s-c] + * Status of an interpreter installation + */ + INTERPRETER_INSTALL_RESULT = 'INTERPRETER_INSTALL_RESULT', + + /** + * [s-c] + * collaborative mode status + */ + COLLABORATIVE_MODE_STATUS = 'COLLABORATIVE_MODE_STATUS', + + /** + * [c-s][s-c] + * patch editor text + */ + PATCH_PARAGRAPH = 'PATCH_PARAGRAPH', + + /** + * [s-c] + * sequential run status will be change + */ + NOTE_RUNNING_STATUS = 'NOTE_RUNNING_STATUS', + + /** + * [s-c] + * Notice + */ + NOTICE = 'NOTICE' +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts new file mode 100644 index 00000000000..bcc01995892 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts @@ -0,0 +1,467 @@ +/* + * 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 { EditorCompletionKey, EditorLanguage, EditorMode } from './message-common.interface'; + +export enum DynamicFormsType { + TextBox = 'TextBox', + Password = 'Password', + Select = 'Select', + CheckBox = 'CheckBox' +} + +export interface DynamicFormsItem { + defaultValue: string | string[]; + hidden: boolean; + name: string; + type: DynamicFormsType; + argument?: string; + options?: Array<{ value: string; displayName?: string }>; +} + +export interface DynamicForms { + [key: string]: DynamicFormsItem; +} + +export interface DynamicFormParams { + [key: string]: string | string[]; +} + +export interface ParagraphEditorSetting { + language?: EditorLanguage; + editOnDblClick?: boolean; + isOutputHidden?: boolean; + completionKey?: EditorCompletionKey; + completionSupport?: boolean; + params?: DynamicFormParams; + forms?: DynamicForms; +} + +// TODO(hsuanxyz) +export interface ParagraphParams { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface ParagraphConfigResults { + [index: string]: ParagraphConfigResult; +} + +export interface ParagraphConfigResult { + graph: GraphConfig; +} + +export interface ParagraphConfig { + editorSetting?: ParagraphEditorSetting; + colWidth?: number; + editorMode?: EditorMode; + fontSize?: number; + results?: ParagraphConfigResults; + enabled?: boolean; + tableHide?: boolean; + lineNumbers?: boolean; + editorHide?: boolean; + title?: boolean; + runOnSelectionChange?: boolean; + isZeppelinNotebookCronEnable?: boolean; +} + +export interface ParagraphResults { + code?: string; + msg?: ParagraphIResultsMsgItem[]; + + [index: number]: {}; +} + +export enum DatasetType { + NETWORK = 'NETWORK', + TABLE = 'TABLE', + HTML = 'HTML', + TEXT = 'TEXT', + ANGULAR = 'ANGULAR', + IMG = 'IMG' +} + +export class ParagraphIResultsMsgItem { + type: DatasetType = DatasetType.TEXT; + data = ''; +} + +export interface ParasInfo { + id: string; + infos: RuntimeInfos; +} + +export interface RuntimeInfos { + jobUrl: RuntimeInfosJobUrl; +} + +interface RuntimeInfosJobUrl { + propertyName: string; + label: string; + tooltip: string; + group: string; + values: RuntimeInfosValuesItem[]; + interpreterSettingId: string; +} + +interface RuntimeInfosValuesItem { + jobUrl: string; +} + +export interface ParagraphItem { + text: string; + user: string; + dateUpdated: string; + config: ParagraphConfig; + settings: ParagraphEditorSetting; + results?: ParagraphResults; + // tslint:disable-next-line no-any + apps: any[]; + progressUpdateIntervalMs: number; + jobName: string; + id: string; + dateCreated: string; + dateStarted?: string; + dateFinished?: string; + errorMessage?: string; + runtimeInfos?: RuntimeInfos; + status: string; + title?: string; + focus?: boolean; + // tslint:disable-next-line no-any TODO(hsuanxyz) + aborted: any; + // tslint:disable-next-line no-any TODO(hsuanxyz) + lineNumbers: any; + // tslint:disable-next-line no-any TODO(hsuanxyz) + fontSize: any; +} + +export interface SendParagraph { + id: string; + title?: string; + paragraph: string; + config: ParagraphConfig; + params: ParagraphParams; +} + +export interface CopyParagraph { + index: number; + title?: string; + paragraph: string; + config: ParagraphConfig; + params: ParagraphParams; +} + +export interface RunParagraph extends SendParagraph { + // tslint:disable-next-line no-any + [key: string]: any; +} + +export interface CommitParagraph extends SendParagraph { + noteId: string; +} + +export interface RunAllParagraphs { + noteId: string; + paragraphs: string; +} + +export interface InsertParagraph { + index: number; +} + +export interface MoveParagraph { + id: string; + index: number; +} + +export interface AngularObjectUpdated { + noteId: string; + paragraphId: string; + name: string; + value: string; + interpreterGroupId: string; +} + +export interface AngularObjectRemove { + noteId: string; + paragraphId: string; + name: string; +} + +export interface AngularObjectUpdate { + noteId: string; + paragraphId: string; + interpreterGroupId: string; + angularObject: { + name: string; + // tslint:disable-next-line:no-any + object: any; + noteId: string; + paragraphId: string; + }; +} + +export interface AngularObjectClientBind { + noteId: string; + name: string; + value: string; + paragraphId: string; +} + +export interface AngularObjectClientUnbind { + noteId: string; + name: string; + paragraphId: string; +} + +export interface CancelParagraph { + id: string; +} + +export interface ParagraphRemove { + id: string; +} + +export interface ParagraphClearOutput { + id: string; +} + +export interface ParagraphClearAllOutput { + id: string; +} + +export interface Completion { + id: string; + buf: string; + cursor: number; +} + +export interface CompletionItem { + meta: string; + value: string; + name: string; +} + +export interface CompletionReceived { + completions: CompletionItem[]; + id: string; +} + +export interface PatchParagraphReceived { + id: string; + noteId: string; + patch: string; +} + +export interface PatchParagraphSend { + paragraphId: string; + patch: string; +} + +export interface ParagraphRemoved { + id: string; +} + +export type VisualizationMode = + | 'table' + | 'lineChart' + | 'stackedAreaChart' + | 'multiBarChart' + | 'scatterChart' + | 'pieChart' + | string; + +export class GraphConfig { + mode: VisualizationMode = 'table'; + height = 300; + optionOpen = false; + setting: GraphConfigSetting = {}; + keys: GraphConfigKeysItem[] = []; + groups: GraphConfigGroupsItem[] = []; + values: GraphConfigValuesItem[] = []; + commonSetting: GraphConfigCommonSetting; +} + +export interface Progress { + id: string; + progress: number; +} + +interface GraphConfigSetting { + table?: VisualizationTable; + lineChart?: VisualizationLineChart; + stackedAreaChart?: VisualizationStackedAreaChart; + multiBarChart?: VisualizationMultiBarChart; + scatterChart?: VisualizationScatterChart; +} + +interface VisualizationTable { + tableGridState: TableGridState; + tableColumnTypeState: TableColumnTypeState; + updated: boolean; + initialized: boolean; + tableOptionSpecHash: string; + tableOptionValue: TableOptionValue; +} + +interface TableGridState { + columns: ColumnsItem[]; + scrollFocus: ScrollFocus; + // tslint:disable-next-line + selection: any[]; + grouping: Grouping; + treeView: TreeView; + pagination: Pagination; +} + +interface ColumnsItem { + name: string; + visible: boolean; + width: string; + sort: Sort; + filters: FiltersItem[]; + pinned: string; +} + +interface Sort { + // tslint:disable-next-line + [key: string]: any; +} + +interface FiltersItem { + // tslint:disable-next-line + [key: string]: any; +} + +interface ScrollFocus { + // tslint:disable-next-line + [key: string]: any; +} + +interface Grouping { + // tslint:disable-next-line + grouping: any[]; + // tslint:disable-next-line + aggregations: any[]; + rowExpandedStates: RowExpandedStates; +} + +interface RowExpandedStates { + // tslint:disable-next-line + [key: string]: any; +} + +interface TreeView { + // tslint:disable-next-line + [key: string]: any; +} + +interface Pagination { + paginationCurrentPage: number; + paginationPageSize: number; +} + +interface TableColumnTypeState { + updated: boolean; + names: Names; +} + +interface Names { + index: string; + value: string; + random: string; + count: string; +} + +interface TableOptionValue { + useFilter: boolean; + showPagination: boolean; + showAggregationFooter: boolean; +} + +export type XLabelStatus = 'default' | 'rotate' | 'hide'; + +export class XAxisSetting { + rotate = { degree: '-45' }; + xLabelStatus: XLabelStatus = 'default'; +} + +export class VisualizationLineChart extends XAxisSetting { + forceY = false; + lineWithFocus = false; + isDateFormat = false; + dateFormat = ''; +} + +export class VisualizationStackedAreaChart extends XAxisSetting { + style: 'stream' | 'expand' | 'stack' = 'stack'; +} + +export class VisualizationMultiBarChart extends XAxisSetting { + stacked = false; +} + +export class VisualizationScatterChart { + xAxis?: XAxis; + yAxis?: YAxis; + group?: Group; + size?: Size; +} + +interface XAxis { + name: string; + index: number; + aggr: string; +} + +interface YAxis { + name: string; + index: number; + aggr: string; +} + +interface Group { + name: string; + index: number; + aggr: string; +} + +interface Size { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigKeysItem { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigGroupsItem { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigValuesItem { + name: string; + index: number; + aggr: string; +} + +interface GraphConfigCommonSetting { + // tslint:disable-next-line + [key: string]: any; +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts new file mode 100644 index 00000000000..4160fa7f035 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export * from './message-common.interface'; +export * from './message-data-type-map.interface'; +export * from './message-notebook.interface'; +export * from './message-operator.interface'; +export * from './message-paragraph.interface'; +export * from './websocket-message.interface'; +export * from './message-job.interface'; +export * from './message-interpreter.interface'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts new file mode 100644 index 00000000000..bdc71e1f428 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/websocket-message.interface.ts @@ -0,0 +1,21 @@ +/* + * 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 { MixMessageDataTypeMap } from './message-data-type-map.interface'; + +export interface WebSocketMessage { + op: K; + data?: MixMessageDataTypeMap[K]; + ticket?: string; // default 'anonymous' + principal?: string; // default 'anonymous' + roles?: string; // default '[]' +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts new file mode 100644 index 00000000000..65ceec605de --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts @@ -0,0 +1,502 @@ +/* + * 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 { interval, Observable, Subject, Subscription } from 'rxjs'; +import { delay, filter, map, mergeMap, retryWhen, take } from 'rxjs/operators'; +import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; + +import { Ticket } from './interfaces/message-common.interface'; +import { + MessageReceiveDataTypeMap, + MessageSendDataTypeMap, + MixMessageDataTypeMap +} from './interfaces/message-data-type-map.interface'; +import { NoteConfig, PersonalizedMode, SendNote } from './interfaces/message-notebook.interface'; +import { OP } from './interfaces/message-operator.interface'; +import { ParagraphConfig, ParagraphParams, SendParagraph } from './interfaces/message-paragraph.interface'; +import { WebSocketMessage } from './interfaces/websocket-message.interface'; + +export type ArgumentsType = T extends (...args: infer U) => void ? U : never; + +export type SendArgumentsType = MessageSendDataTypeMap[K] extends undefined + ? ArgumentsType<(op: K) => void> + : ArgumentsType<(op: K, data: MessageSendDataTypeMap[K]) => void>; + +export type ReceiveArgumentsType< + K extends keyof MessageReceiveDataTypeMap +> = MessageReceiveDataTypeMap[K] extends undefined ? () => void : (data?: MessageReceiveDataTypeMap[K]) => void; + +export class Message { + public connectedStatus = false; + public connectedStatus$ = new Subject(); + private ws: WebSocketSubject>; + private open$ = new Subject(); + private close$ = new Subject(); + private sent$ = new Subject>(); + private received$ = new Subject>(); + private pingIntervalSubscription = new Subscription(); + private wsUrl: string; + private ticket: Ticket; + + constructor() { + this.open$.subscribe(() => { + this.connectedStatus = true; + this.connectedStatus$.next(this.connectedStatus); + this.pingIntervalSubscription.unsubscribe(); + this.pingIntervalSubscription = interval(1000 * 10).subscribe(() => this.ping()); + }); + this.close$.subscribe(() => { + this.connectedStatus = false; + this.connectedStatus$.next(this.connectedStatus); + this.pingIntervalSubscription.unsubscribe(); + }); + } + + bootstrap(ticket: Ticket, wsUrl: string) { + this.setTicket(ticket); + this.setWsUrl(wsUrl); + this.connect(); + } + + getWsInstance(): WebSocketSubject> { + return this.ws; + } + + setWsUrl(wsUrl: string): void { + this.wsUrl = wsUrl; + } + + setTicket(ticket: Ticket): void { + this.ticket = ticket; + } + + interceptReceived( + data: WebSocketMessage + ): WebSocketMessage { + return data; + } + + connect() { + this.ws = webSocket({ + url: this.wsUrl, + openObserver: this.open$, + closeObserver: this.close$ + }); + + this.ws + .pipe( + // reconnect + retryWhen(errors => + errors.pipe( + mergeMap(() => + this.close$.pipe( + take(1), + delay(4000) + ) + ) + ) + ) + ) + .subscribe((e: WebSocketMessage) => { + console.log('Receive:', e); + this.received$.next(this.interceptReceived(e)); + }); + } + + ping() { + this.send(OP.PING); + } + + opened(): Observable { + return this.open$.asObservable(); + } + + closed(): Observable { + return this.close$.asObservable(); + } + + sent(): Observable> { + return this.sent$.asObservable(); + } + + received(): Observable> { + return this.received$.asObservable(); + } + + send(...args: SendArgumentsType): void { + const [op, data] = args; + const message: WebSocketMessage = { + op, + data: data as MixMessageDataTypeMap[K], + ...this.ticket + }; + console.log('Send:', message); + + this.ws.next(message); + this.sent$.next(message); + } + + receive(op: K): Observable[K]> { + return this.received$.pipe( + filter(message => message.op === op), + map(message => message.data) + ) as Observable[K]>; + } + + destroy(): void { + this.ws.complete(); + this.ws = null; + } + + getHomeNote(): void { + this.send(OP.GET_HOME_NOTE); + } + + newNote(noteName: string, defaultInterpreterGroup: string): void { + this.send(OP.NEW_NOTE, { + name: noteName, + defaultInterpreterGroup + }); + } + + moveNoteToTrash(noteId: string): void { + this.send(OP.MOVE_NOTE_TO_TRASH, { + id: noteId + }); + } + + restoreNote(noteId: string): void { + this.send(OP.RESTORE_NOTE, { + id: noteId + }); + } + + deleteNote(noteId): void { + this.send(OP.DEL_NOTE, { + id: noteId + }); + } + + restoreFolder(folderPath: string): void { + this.send(OP.RESTORE_FOLDER, { + id: folderPath + }); + } + + removeFolder(folderPath: string): void { + this.send(OP.REMOVE_FOLDER, { + id: folderPath + }); + } + + moveFolderToTrash(folderPath: string): void { + this.send(OP.MOVE_FOLDER_TO_TRASH, { + id: folderPath + }); + } + + restoreAll(): void { + this.send(OP.RESTORE_ALL); + } + + emptyTrash(): void { + this.send(OP.EMPTY_TRASH); + } + + cloneNote(noteIdToClone, newNoteName): void { + this.send(OP.CLONE_NOTE, { id: noteIdToClone, name: newNoteName }); + } + + /** + * get nodes list + */ + listNodes(): void { + this.send(OP.LIST_NOTES); + } + + reloadAllNotesFromRepo(): void { + this.send(OP.RELOAD_NOTES_FROM_REPO); + } + + getNote(noteId: string): void { + this.send(OP.GET_NOTE, { id: noteId }); + } + + updateNote(noteId: string, noteName: string, noteConfig: NoteConfig): void { + this.send(OP.NOTE_UPDATE, { id: noteId, name: noteName, config: noteConfig }); + } + + updatePersonalizedMode(noteId: string, modeValue: PersonalizedMode): void { + this.send(OP.UPDATE_PERSONALIZED_MODE, { id: noteId, personalized: modeValue }); + } + + noteRename(noteId: string, noteName: string, relative: boolean): void { + this.send(OP.NOTE_RENAME, { id: noteId, name: noteName, relative: relative }); + } + + folderRename(folderId: string, folderPath: string): void { + this.send(OP.FOLDER_RENAME, { id: folderId, name: folderPath }); + } + + moveParagraph(paragraphId: string, newIndex: number): void { + this.send(OP.MOVE_PARAGRAPH, { id: paragraphId, index: newIndex }); + } + + insertParagraph(newIndex: number): void { + this.send(OP.INSERT_PARAGRAPH, { index: newIndex }); + } + + copyParagraph( + newIndex: number, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + this.send(OP.COPY_PARAGRAPH, { + index: newIndex, + title: paragraphTitle, + paragraph: paragraphData, + config: paragraphConfig, + params: paragraphParams + }); + } + + angularObjectUpdate( + noteId: string, + paragraphId: string, + name: string, + value: string, + interpreterGroupId: string + ): void { + this.send(OP.ANGULAR_OBJECT_UPDATED, { + noteId: noteId, + paragraphId: paragraphId, + name: name, + value: value, + interpreterGroupId: interpreterGroupId + }); + } + + // tslint:disable-next-line:no-any + angularObjectClientBind(noteId: string, name: string, value: any, paragraphId: string): void { + this.send(OP.ANGULAR_OBJECT_CLIENT_BIND, { + noteId: noteId, + name: name, + value: value, + paragraphId: paragraphId + }); + } + + angularObjectClientUnbind(noteId: string, name: string, paragraphId: string): void { + this.send(OP.ANGULAR_OBJECT_CLIENT_UNBIND, { + noteId: noteId, + name: name, + paragraphId: paragraphId + }); + } + + cancelParagraph(paragraphId): void { + this.send(OP.CANCEL_PARAGRAPH, { id: paragraphId }); + } + + paragraphExecutedBySpell( + paragraphId, + paragraphTitle, + paragraphText, + paragraphResultsMsg, + paragraphStatus, + paragraphErrorMessage, + paragraphConfig, + paragraphParams, + paragraphDateStarted, + paragraphDateFinished + ): void { + this.send(OP.PARAGRAPH_EXECUTED_BY_SPELL, { + id: paragraphId, + title: paragraphTitle, + paragraph: paragraphText, + results: { + code: paragraphStatus, + msg: paragraphResultsMsg.map(dataWithType => { + const serializedData = dataWithType.data; + return { type: dataWithType.type, serializedData }; + }) + }, + status: paragraphStatus, + errorMessage: paragraphErrorMessage, + config: paragraphConfig, + params: paragraphParams, + dateStarted: paragraphDateStarted, + dateFinished: paragraphDateFinished + }); + } + + runParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + this.send(OP.RUN_PARAGRAPH, { + id: paragraphId, + title: paragraphTitle, + paragraph: paragraphData, + config: paragraphConfig, + params: paragraphParams + }); + } + + runAllParagraphs(noteId: string, paragraphs: SendParagraph[]): void { + this.send(OP.RUN_ALL_PARAGRAPHS, { + noteId: noteId, + paragraphs: JSON.stringify(paragraphs) + }); + } + + paragraphRemove(paragraphId: string): void { + this.send(OP.PARAGRAPH_REMOVE, { id: paragraphId }); + } + + paragraphClearOutput(paragraphId: string): void { + this.send(OP.PARAGRAPH_CLEAR_OUTPUT, { id: paragraphId }); + } + + paragraphClearAllOutput(noteId: string): void { + this.send(OP.PARAGRAPH_CLEAR_ALL_OUTPUT, { id: noteId }); + } + + completion(paragraphId: string, buf: string, cursor: number): void { + this.send(OP.COMPLETION, { + id: paragraphId, + buf: buf, + cursor: cursor + }); + } + + commitParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphConfig, + noteId: string + ): void { + return this.send(OP.COMMIT_PARAGRAPH, { + id: paragraphId, + noteId: noteId, + title: paragraphTitle, + paragraph: paragraphData, + config: paragraphConfig, + params: paragraphParams + }); + } + + patchParagraph(paragraphId: string, noteId: string, patch: string): void { + // javascript add "," if change contains several patches + // but java library requires patch list without "," + const normalPatch = patch.replace(/,@@/g, '@@'); + return this.send(OP.PATCH_PARAGRAPH, { + id: paragraphId, + noteId: noteId, + patch: normalPatch + }); + } + + importNote(note: SendNote): void { + this.send(OP.IMPORT_NOTE, { + note: note + }); + } + + checkpointNote(noteId: string, commitMessage: string): void { + this.send(OP.CHECKPOINT_NOTE, { + noteId: noteId, + commitMessage: commitMessage + }); + } + + setNoteRevision(noteId: string, revisionId: string): void { + this.send(OP.SET_NOTE_REVISION, { + noteId: noteId, + revisionId: revisionId + }); + } + + listRevisionHistory(noteId: string): void { + this.send(OP.LIST_REVISION_HISTORY, { + noteId: noteId + }); + } + + noteRevision(noteId: string, revisionId: string): void { + this.send(OP.NOTE_REVISION, { + noteId: noteId, + revisionId: revisionId + }); + } + + noteRevisionForCompare(noteId: string, revisionId: string, position: string): void { + this.send(OP.NOTE_REVISION_FOR_COMPARE, { + noteId: noteId, + revisionId: revisionId, + position: position + }); + } + + editorSetting(paragraphId: string, replName: string): void { + this.send(OP.EDITOR_SETTING, { + paragraphId: paragraphId, + magic: replName + }); + } + + listNoteJobs(): void { + this.send(OP.LIST_NOTE_JOBS); + } + + unsubscribeUpdateNoteJobs(): void { + this.send(OP.UNSUBSCRIBE_UPDATE_NOTE_JOBS); + } + + getInterpreterBindings(noteId: string): void { + this.send(OP.GET_INTERPRETER_BINDINGS, { noteId: noteId }); + } + + saveInterpreterBindings(noteId, selectedSettingIds): void { + // this.send(OP.SAVE_INTERPRETER_BINDINGS, + // {noteId: noteId, selectedSettingIds: selectedSettingIds}); + } + + listConfigurations(): void { + this.send(OP.LIST_CONFIGURATIONS); + } + + getInterpreterSettings(): void { + this.send(OP.GET_INTERPRETER_SETTINGS); + } + + saveNoteForms(note: SendNote): void { + this.send(OP.SAVE_NOTE_FORMS, { + noteId: note.id, + noteParams: note.noteParams + }); + } + + removeNoteForms(note, formName): void { + this.send(OP.REMOVE_NOTE_FORMS, { + noteId: note.id, + formName: formName + }); + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts new file mode 100644 index 00000000000..c5417873004 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/public-api.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export * from './message'; +// https://github.com/ng-packagr/ng-packagr/issues/1093 +export * from './interfaces/public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json new file mode 100644 index 00000000000..784751866f8 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "flatModuleId": "@zeppelin/sdk" + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tslint.json b/zeppelin-web-angular/projects/zeppelin-sdk/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-sdk/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/README.md b/zeppelin-web-angular/projects/zeppelin-visualization/README.md new file mode 100644 index 00000000000..aa8e560c926 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/README.md @@ -0,0 +1,36 @@ + + +# ZeppelinVisualization + +This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.8. + +## Code scaffolding + +Run `ng generate component component-name --project zeppelin-visualization` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project zeppelin-visualization`. +> Note: Don't forget to add `--project zeppelin-visualization` or else it will be added to the default project in your `angular.json` file. + +## Build + +Run `ng build zeppelin-visualization` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Publishing + +After building your library with `ng build zeppelin-visualization`, go to the dist folder `cd dist/zeppelin-visualization` and run `npm publish`. + +## Running unit tests + +Run `ng test zeppelin-visualization` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js b/zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js new file mode 100644 index 00000000000..e04c06a8f52 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/karma.conf.js @@ -0,0 +1,44 @@ +/* + * 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. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../../coverage/zeppelin-visualization'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json b/zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json new file mode 100644 index 00000000000..78b3ecf185e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/zeppelin-visualization", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/package.json b/zeppelin-web-angular/projects/zeppelin-visualization/package.json new file mode 100644 index 00000000000..1d4232be543 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/package.json @@ -0,0 +1,8 @@ +{ + "name": "@zeppelin/visualization", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^8.2.8", + "@angular/core": "^8.2.8" + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts new file mode 100644 index 00000000000..98d4632fcab --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/data-set.ts @@ -0,0 +1,17 @@ +/* + * 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 { ParagraphIResultsMsgItem } from '@zeppelin/sdk'; + +export abstract class DataSet { + abstract loadParagraphResult(paragraphResult: ParagraphIResultsMsgItem): void; +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts new file mode 100644 index 00000000000..d663788be0e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-base.ts @@ -0,0 +1,57 @@ +/* + * 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 { GraphConfig } from '@zeppelin/sdk'; + +import { G2VisualizationComponentBase } from './g2-visualization-component-base'; +import { PivotTransformation } from './pivot-transformation'; +import { Transformation } from './transformation'; +import { Visualization } from './visualization'; +import { VisualizationComponentPortal } from './visualization-component-portal'; + +export abstract class G2VisualizationBase extends Visualization { + pivot = new PivotTransformation(this.getConfig()); + abstract componentPortal: VisualizationComponentPortal; + + constructor(config: GraphConfig) { + super(config); + } + + destroy(): void { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + } + + getTransformation(): Transformation { + return this.pivot; + } + + refresh(): void { + if (this.componentRef) { + this.componentRef.instance.refresh(); + } + } + + render(data): void { + this.transformed = data; + if (this.componentRef) { + this.componentRef.instance.refreshSetting(); + this.componentRef.instance.render(); + } else { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts new file mode 100644 index 00000000000..8e52dcdc9de --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts @@ -0,0 +1,93 @@ +/* + * 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 { ElementRef, OnDestroy } from '@angular/core'; + +import * as G2 from '@antv/g2'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { Visualization } from './visualization'; + +export abstract class G2VisualizationComponentBase implements OnDestroy { + abstract container: ElementRef; + chart: G2.Chart; + config: GraphConfig; + + constructor(public visualization: Visualization) {} + + abstract renderBefore(chart: G2.Chart): void; + + abstract refreshSetting(): void; + abstract setScale(): void; + + render() { + this.config = this.visualization.getConfig(); + this.refreshSetting(); + this.initChart(); + this.chart.source(this.visualization.transformed); + this.renderBefore(this.chart); + this.chart.render(); + this.renderAfter(); + } + + renderAfter(): void {} + + getKey(): string { + let key = ''; + if (this.config.keys && this.config.keys[0]) { + key = this.config.keys[0].name; + } + return key; + } + + refresh(): void { + this.config = this.visualization.getConfig(); + this.chart.changeHeight(this.config.height || 400); + setTimeout(() => { + this.setScale(); + this.chart.forceFit(); + }); + } + + initChart() { + if (this.chart) { + this.chart.clear(); + } else { + if (this.container && this.container.nativeElement) { + this.chart = new G2.Chart({ + forceFit: true, + container: this.container.nativeElement, + height: this.config.height || 400, + padding: { + top: 80, + left: 50, + right: 50, + bottom: 50 + } + }); + this.chart.legend({ + position: 'top-right' + // tslint:disable-next-line + } as any); + } else { + throw new Error(`Can't find the container, Please make sure on correct assignment.`); + } + } + } + + ngOnDestroy(): void { + if (this.chart) { + this.chart.destroy(); + this.chart = null; + } + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts new file mode 100644 index 00000000000..cade722cd81 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts @@ -0,0 +1,199 @@ +/* + * 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 { DataSet } from '@antv/data-set'; +import { get } from 'lodash'; + +import { TableData } from './table-data'; +import { Transformation } from './transformation'; + +// tslint:disable-next-line:no-any +export class PivotTransformation extends Transformation { + constructor(config) { + super(config); + } + + removeUnknown(array: Array<{ name: string }>, tableData: TableData): void { + for (let i = 0; i < array.length; i++) { + // remove non existing column + let found = false; + for (let j = 0; j < tableData.columns.length; j++) { + const a = array[i]; + const b = tableData.columns[j]; + if (a.name === b) { + found = true; + break; + } + } + if (!found) { + array.splice(i, 1); + i--; + } + } + } + + setDefaultConfig(tableData: TableData) { + const config = this.getConfig(); + config.keys = config.keys || []; + config.groups = config.groups || []; + config.values = config.values || []; + this.removeUnknown(config.keys, tableData); + this.removeUnknown(config.values, tableData); + this.removeUnknown(config.groups, tableData); + if (config.keys.length === 0 && config.groups.length === 0 && config.values.length === 0) { + if (config.keys.length === 0 && tableData.columns[0]) { + config.keys = [ + { + name: tableData.columns[0], + index: 0, + aggr: 'sum' + } + ]; + } + + if (config.values.length === 0 && tableData.columns[1]) { + config.values = [ + { + name: tableData.columns[1], + index: 1, + aggr: 'sum' + } + ]; + } + } + } + + // tslint:disable-next-line:no-any + transform(tableData: TableData): any { + const config = this.getConfig(); + this.setDefaultConfig(tableData); + const ds = new DataSet(); + let dv = ds.createView().source(tableData.rows); + + let firstKey = ''; + if (config.keys && config.keys[0]) { + firstKey = config.keys[0].name; + } + let keys = []; + let groups = []; + let values = []; + let aggregates = []; + if (config.mode !== 'scatterChart') { + keys = config.keys.map(e => e.name); + groups = config.groups.map(e => e.name); + values = config.values.map(v => `${v.name}(${v.aggr})`); + aggregates = config.values.map(v => (v.aggr === 'avg' ? 'mean' : v.aggr)); + } else { + const xAxis = get(config.setting, 'scatterChart.xAxis.name', tableData.columns[0]); + const yAxis = get(config.setting, 'scatterChart.yAxis.name', tableData.columns[1]); + const group = get(config.setting, 'scatterChart.group.name'); + keys = xAxis ? [xAxis] : []; + values = yAxis ? [yAxis] : []; + groups = group ? [group] : []; + } + + dv.transform({ + type: 'map', + callback: row => { + Object.keys(row).forEach(k => { + if (config.keys.map(e => e.name).indexOf(k) === -1) { + const numberValue = Number.parseFloat(row[k]); + row[k] = Number.isFinite(numberValue) ? numberValue : row[k]; + } + }); + return row; + } + }); + + if (config.mode !== 'scatterChart') { + dv.transform({ + type: 'aggregate', + fields: config.values.map(v => v.name), + operations: aggregates, + as: values, + groupBy: [...keys, ...groups] + }); + + // dv.transform({ + // type: 'fill-rows', + // groupBy: groups, + // orderBy: keys, + // fillBy: 'order' + // }); + + dv.transform({ + type: 'fill-rows', + groupBy: [...keys, ...groups], + fillBy: 'group' + }); + + config.values + .map(v => `${v.name}(${v.aggr})`) + .forEach(field => { + dv.transform({ + field, + type: 'impute', + groupBy: keys, + method: 'value', + value: config.mode === 'stackedAreaChart' ? 0 : null + }); + }); + } + + dv.transform({ + type: 'fold', + fields: values, + key: '__key__', + value: '__value__' + }); + + dv.transform({ + type: 'partition', + groupBy: groups + }); + + const groupsData = []; + Object.keys(dv.rows).forEach(groupKey => { + const groupName = groupKey.replace(/^_/, ''); + dv.rows[groupKey].forEach(row => { + groupsData.push({ + ...row, + __key__: groupName ? `${row.__key__}.${groupName}` : row.__key__ + }); + }); + }); + + groupsData.sort( + (a, b) => + dv.origin.findIndex(o => o[firstKey] === a[firstKey]) - dv.origin.findIndex(o => o[firstKey] === b[firstKey]) + ); + + dv = ds + .createView({ + state: { + filterData: null + } + }) + .source(groupsData); + + if (config.mode === 'stackedAreaChart' || config.mode === 'pieChart') { + dv.transform({ + type: 'percent', + field: '__value__', + dimension: '__key__', + groupBy: keys, + as: '__percent__' + }); + } + return dv; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts new file mode 100644 index 00000000000..c28b0e2a649 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +/* + * Public API Surface of zeppelin-visualization + */ + +export * from './data-set'; +export * from './transformation'; +export * from './visualization-component-portal'; +export * from './visualization'; +export * from './table-data'; +export * from './table-transformation'; +export * from './pivot-transformation'; +export * from './g2-visualization-base'; +export * from './g2-visualization-component-base'; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts new file mode 100644 index 00000000000..f0bd5ad4227 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-data.ts @@ -0,0 +1,35 @@ +/* + * 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 { DataSet as AntvDataSet } from '@antv/data-set'; + +import { DatasetType, ParagraphIResultsMsgItem } from '@zeppelin/sdk'; +import { DataSet } from './data-set'; + +export class TableData extends DataSet { + columns: string[] = []; + // tslint:disable-next-line + rows: any[] = []; + + loadParagraphResult({ data, type }: ParagraphIResultsMsgItem): void { + if (type !== DatasetType.TABLE) { + console.error('Can not load paragraph result'); + return; + } + const ds = new AntvDataSet(); + const dv = ds.createView().source(data, { + type: 'tsv' + }); + this.columns = dv.origin && dv.origin.columns ? dv.origin.columns : []; + this.rows = dv.rows || []; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts new file mode 100644 index 00000000000..19111ecad88 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts @@ -0,0 +1,26 @@ +/* + * 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 { TableData } from './table-data'; +import { Transformation } from './transformation'; + +// tslint:disable-next-line:no-any +export class TableTransformation extends Transformation { + constructor(config) { + super(config); + } + + // tslint:disable-next-line:no-any + transform(tableData: TableData): any { + return tableData; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts new file mode 100644 index 00000000000..522ac021326 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/transformation.ts @@ -0,0 +1,46 @@ +/* + * 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 { GraphConfig } from '@zeppelin/sdk'; + +import { DataSet } from './data-set'; + +export interface Setting { + // tslint:disable-next-line:no-any + template: any; + // tslint:disable-next-line:no-any + scope: any; +} + +export abstract class Transformation { + dataset: DataSet; + constructor(private config: GraphConfig) {} + + // tslint:disable-next-line:no-any + abstract transform(tableData): any; + + setConfig(config) { + this.config = config; + } + + setTableData(dataset: DataSet) { + this.dataset = dataset; + } + + getTableData(): DataSet { + return this.dataset; + } + + getConfig() { + return this.config; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts new file mode 100644 index 00000000000..a9418d98307 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts @@ -0,0 +1,46 @@ +/* + * 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 { CdkPortalOutlet, ComponentPortal, ComponentType, PortalInjector } from '@angular/cdk/portal'; +import { ComponentFactoryResolver, InjectionToken, ViewContainerRef } from '@angular/core'; + +import { Visualization } from './visualization'; + +export const VISUALIZATION = new InjectionToken('Visualization'); + +export class VisualizationComponentPortal { + constructor( + private visualization: T, + private component: ComponentType, + private portalOutlet: CdkPortalOutlet, + private viewContainerRef: ViewContainerRef, + private componentFactoryResolver?: ComponentFactoryResolver + ) {} + + createInjector() { + const userInjector = this.viewContainerRef && this.viewContainerRef.injector; + // tslint:disable-next-line + const injectionTokens = new WeakMap([[VISUALIZATION, this.visualization]]); + return new PortalInjector(userInjector, injectionTokens); + } + + getComponentPortal() { + const injector = this.createInjector(); + return new ComponentPortal(this.component, null, injector, this.componentFactoryResolver); + } + + attachComponentPortal() { + const componentRef = this.portalOutlet.attachComponentPortal(this.getComponentPortal()); + componentRef.changeDetectorRef.markForCheck(); + return componentRef; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts new file mode 100644 index 00000000000..bb483e58766 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization.ts @@ -0,0 +1,44 @@ +/* + * 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 { ComponentRef } from '@angular/core'; +import { Subject } from 'rxjs'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { Transformation } from './transformation'; + +// tslint:disable-next-line +export abstract class Visualization { + // tslint:disable-next-line + transformed: any; + componentRef: ComponentRef; + configChange$ = new Subject(); + constructor(private config: GraphConfig) {} + + abstract getTransformation(): Transformation; + abstract render(tableData): void; + abstract refresh(): void; + abstract destroy(): void; + + configChanged() { + return this.configChange$.asObservable(); + } + + setConfig(config: GraphConfig) { + this.config = config; + this.refresh(); + } + + getConfig() { + return this.config; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json new file mode 100644 index 00000000000..15689086f6e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "angularCompilerOptions": { + "annotateForClosureCompiler": true, + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true, + "enableResourceInlining": true, + "flatModuleId": "@zeppelin/visualization" + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json new file mode 100644 index 00000000000..16da33db072 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.spec.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/tslint.json b/zeppelin-web-angular/projects/zeppelin-visualization/tslint.json new file mode 100644 index 00000000000..124133f8499 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-visualization/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "lib", + "camelCase" + ], + "component-selector": [ + true, + "element", + "lib", + "kebab-case" + ] + } +} diff --git a/zeppelin-web-angular/proxy.conf.js b/zeppelin-web-angular/proxy.conf.js new file mode 100644 index 00000000000..c3d571ce3e5 --- /dev/null +++ b/zeppelin-web-angular/proxy.conf.js @@ -0,0 +1,59 @@ +/* + * 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. + */ + +const dotenv = require('dotenv'); +const HttpsProxyAgent = require('https-proxy-agent'); +dotenv.config(); + +const proxyConfig = [ + { + context: ['/'], + target: 'http://localhost:8080', + secure: false, + changeOrigin: true + }, + { + context: '/ws', + target: 'ws://localhost:8080', + secure: false, + ws:true, + changeOrigin: true + } +]; + +function httpUrlToWSUrl(url) { + return url.replace(/(http)(s)?\:\/\//, "ws$2://"); +} + +function setupForCorporateProxy(proxyConfig) { + const proxyServer = process.env.SERVER_PROXY; + const httpProxy = process.env.HTTP_PROXY; + if (proxyServer) { + let agent = null; + if (httpProxy) { + agent = new HttpsProxyAgent(httpProxy); + } + proxyConfig.forEach(function(entry) { + if (entry.context === '/ws') { + entry.target = httpUrlToWSUrl(proxyServer) + } else { + entry.target = proxyServer; + } + if (agent) { + entry.agent = agent; + } + }); + } + return proxyConfig; +} + +module.exports = setupForCorporateProxy(proxyConfig); diff --git a/zeppelin-web-angular/screenshot.png b/zeppelin-web-angular/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..4c157c5fdef1d16f1757fd8b744bbf3b41c90a6f GIT binary patch literal 220058 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%0D5iW% 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 literal 0 HcmV?d00001 diff --git a/zeppelin-web-angular/src/.editorconfig b/zeppelin-web-angular/src/.editorconfig new file mode 100644 index 00000000000..8b14efe23aa --- /dev/null +++ b/zeppelin-web-angular/src/.editorconfig @@ -0,0 +1,12 @@ +# Editor configuration, see https://editorconfig.org + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/zeppelin-web-angular/src/.gitignore b/zeppelin-web-angular/src/.gitignore new file mode 100644 index 00000000000..85158b7a442 --- /dev/null +++ b/zeppelin-web-angular/src/.gitignore @@ -0,0 +1,43 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events.json +speed-measure-plugin.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db diff --git a/zeppelin-web-angular/src/app/app-http.interceptor.ts b/zeppelin-web-angular/src/app/app-http.interceptor.ts new file mode 100644 index 00000000000..520eea89418 --- /dev/null +++ b/zeppelin-web-angular/src/app/app-http.interceptor.ts @@ -0,0 +1,53 @@ +/* + * 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 { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { throwError, Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; + +import { isNil } from 'lodash'; + +import { environment } from '@zeppelin/environment'; +import { TicketService } from '@zeppelin/services'; + +@Injectable() +export class AppHttpInterceptor implements HttpInterceptor { + constructor(private ticketService: TicketService) {} + + // tslint:disable-next-line:no-any + intercept(httpRequest: HttpRequest, next: HttpHandler): Observable> { + let httpRequestUpdated = httpRequest.clone({ withCredentials: true }); + if (environment.production) { + httpRequestUpdated = httpRequest.clone({ setHeaders: { 'X-Requested-With': 'XMLHttpRequest' } }); + } + return next.handle(httpRequestUpdated).pipe( + map(event => { + if (event instanceof HttpResponse) { + return event.clone({ body: event.body.body }); + } else { + return event; + } + }), + catchError(event => { + const redirect = event.headers.get('Location'); + if (event.status === 401 && !isNil(redirect)) { + // Handle page redirect + window.location.href = redirect; + } else if (event.status === 405 && !event.url.contains('logout')) { + this.ticketService.logout().subscribe(); + } + return throwError(event); + }) + ); + } +} diff --git a/zeppelin-web-angular/src/app/app-message.interceptor.ts b/zeppelin-web-angular/src/app/app-message.interceptor.ts new file mode 100644 index 00000000000..0e9843d8960 --- /dev/null +++ b/zeppelin-web-angular/src/app/app-message.interceptor.ts @@ -0,0 +1,68 @@ +/* + * 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 { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +import { NzModalService, NzNotificationService } from 'ng-zorro-antd'; + +import { MessageInterceptor } from '@zeppelin/interfaces'; +import { MessageReceiveDataTypeMap, OP, WebSocketMessage } from '@zeppelin/sdk'; +import { TicketService } from '@zeppelin/services'; + +@Injectable() +export class AppMessageInterceptor implements MessageInterceptor { + constructor( + private router: Router, + private nzNotificationService: NzNotificationService, + private ticketService: TicketService, + private nzModalService: NzModalService + ) {} + + received(data: WebSocketMessage): WebSocketMessage { + if (data.op === OP.NEW_NOTE) { + const rData = data.data as MessageReceiveDataTypeMap[OP.NEW_NOTE]; + this.router.navigate(['/notebook', rData.note.id]).then(); + } else if (data.op === OP.AUTH_INFO) { + const rData = data.data as MessageReceiveDataTypeMap[OP.AUTH_INFO]; + if (this.ticketService.ticket.roles === '[]') { + this.nzModalService.confirm({ + nzClosable: false, + nzMaskClosable: false, + nzTitle: 'Insufficient privileges', + nzContent: rData.info + }); + } else { + this.nzModalService.create({ + nzClosable: false, + nzMaskClosable: false, + nzTitle: 'Insufficient privileges', + nzContent: rData.info, + nzOkText: 'Login', + nzOnOk: () => { + this.router.navigate(['/login']).then(); + }, + nzOnCancel: () => { + this.router.navigate(['/']).then(); + } + }); + } + } else if (data.op === OP.ERROR_INFO) { + // tslint:disable-next-line:no-any + const rData = (data.data as any) as MessageReceiveDataTypeMap[OP.ERROR_INFO]; + if (rData.info) { + this.nzNotificationService.warning('ERROR', rData.info); + } + } + return data; + } +} diff --git a/zeppelin-web-angular/src/app/app-routing.module.ts b/zeppelin-web-angular/src/app/app-routing.module.ts new file mode 100644 index 00000000000..4a580cf9c8f --- /dev/null +++ b/zeppelin-web-angular/src/app/app-routing.module.ts @@ -0,0 +1,36 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { PreloadAllModules, RouterModule, Routes } from '@angular/router'; + +const routes: Routes = [ + { + path: '', + loadChildren: () => import('./pages/workspace/workspace.module').then(m => m.WorkspaceModule) + }, + { + path: 'login', + loadChildren: () => import('./pages/login/login.module').then(m => m.LoginModule) + } +]; + +@NgModule({ + imports: [ + RouterModule.forRoot(routes, { + useHash: true, + preloadingStrategy: PreloadAllModules + }) + ], + exports: [RouterModule] +}) +export class AppRoutingModule {} diff --git a/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts b/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts new file mode 100644 index 00000000000..bde0d988f2f --- /dev/null +++ b/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts @@ -0,0 +1,41 @@ +/* + * 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 { + Compiler, + CompilerFactory, + CompilerOptions, + COMPILER_OPTIONS, + StaticProvider, + ViewEncapsulation +} from '@angular/core'; +import { JitCompilerFactory } from '@angular/platform-browser-dynamic'; + +const compilerOptions: CompilerOptions = { + useJit: true, + defaultEncapsulation: ViewEncapsulation.None +}; + +export function createCompiler(compilerFactory: CompilerFactory) { + return compilerFactory.createCompiler([compilerOptions]); +} + +export const RUNTIME_COMPILER_PROVIDERS: StaticProvider[] = [ + { provide: COMPILER_OPTIONS, useValue: compilerOptions, multi: true }, + { provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] }, + { provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] } +]; + +// TODO(hsuanxyz) +// buildOptimizer false +// import 'core-js/es7/reflect'; +// https://github.com/angular/angular/issues/27584#issuecomment-446462051 diff --git a/zeppelin-web-angular/src/app/app.component.html b/zeppelin-web-angular/src/app/app.component.html new file mode 100644 index 00000000000..d101c77150d --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.html @@ -0,0 +1,15 @@ + + + +Getting Ticket Data ... +Logging out ... diff --git a/zeppelin-web-angular/src/app/app.component.less b/zeppelin-web-angular/src/app/app.component.less new file mode 100644 index 00000000000..f9587c7330a --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.less @@ -0,0 +1,26 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .content { + background: @layout-body-background; + min-height: 100vh; + display: block; + position: relative; + + &.blur { + filter: blur(6px); + } + } +}); diff --git a/zeppelin-web-angular/src/app/app.component.spec.ts b/zeppelin-web-angular/src/app/app.component.spec.ts new file mode 100644 index 00000000000..3dfbc76cc22 --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.spec.ts @@ -0,0 +1,30 @@ +/* + * 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 { async, TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [RouterTestingModule], + declarations: [AppComponent] + }).compileComponents(); + })); + + it('should create the app', () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.debugElement.componentInstance; + expect(app).toBeTruthy(); + }); +}); diff --git a/zeppelin-web-angular/src/app/app.component.ts b/zeppelin-web-angular/src/app/app.component.ts new file mode 100644 index 00000000000..dc9fcb3afbb --- /dev/null +++ b/zeppelin-web-angular/src/app/app.component.ts @@ -0,0 +1,39 @@ +/* + * 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 { Component } from '@angular/core'; +import { NavigationEnd, NavigationStart, Router } from '@angular/router'; +import { filter, map } from 'rxjs/operators'; + +import { TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.less'] +}) +export class AppComponent { + logout$ = this.ticketService.logout$; + loading$ = this.router.events.pipe( + filter(data => data instanceof NavigationEnd || data instanceof NavigationStart), + map(data => { + if (data instanceof NavigationStart) { + // load ticket when redirect to workspace + return data.url === '/'; + } else if (data instanceof NavigationEnd) { + return false; + } + }) + ); + + constructor(private router: Router, private ticketService: TicketService) {} +} diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts new file mode 100644 index 00000000000..ae3347c350b --- /dev/null +++ b/zeppelin-web-angular/src/app/app.module.ts @@ -0,0 +1,88 @@ +/* + * 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 { registerLocaleData } from '@angular/common'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import en from '@angular/common/locales/en'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { Router, RouterModule } from '@angular/router'; + +import { ZeppelinHeliumModule } from '@zeppelin/helium'; +import { en_US, NzModalService, NzNotificationService, NZ_I18N } from 'ng-zorro-antd'; + +import { MESSAGE_INTERCEPTOR, TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { loadMonacoLanguage } from '@zeppelin/languages'; +import { TicketService } from '@zeppelin/services'; +import { ShareModule } from '@zeppelin/share'; + +import { NZ_CODE_EDITOR_CONFIG } from '@zeppelin/share/code-editor'; +import { AppHttpInterceptor } from './app-http.interceptor'; +import { AppMessageInterceptor } from './app-message.interceptor'; +import { AppRoutingModule } from './app-routing.module'; +import { RUNTIME_COMPILER_PROVIDERS } from './app-runtime-compiler.providers'; +import { AppComponent } from './app.component'; + +export const loadMonaco = () => { + loadMonacoLanguage(); +}; + +registerLocaleData(en); + +@NgModule({ + declarations: [AppComponent], + imports: [ + BrowserModule, + FormsModule, + HttpClientModule, + BrowserAnimationsModule, + ShareModule, + AppRoutingModule, + RouterModule, + ZeppelinHeliumModule + ], + providers: [ + ...RUNTIME_COMPILER_PROVIDERS, + { + provide: NZ_I18N, + useValue: en_US + }, + { + provide: HTTP_INTERCEPTORS, + useClass: AppHttpInterceptor, + multi: true, + deps: [TicketService] + }, + { + provide: NZ_CODE_EDITOR_CONFIG, + useValue: { + defaultEditorOption: { + scrollBeyondLastLine: false + }, + onLoad: loadMonaco + } + }, + { + provide: MESSAGE_INTERCEPTOR, + useClass: AppMessageInterceptor, + deps: [Router, NzNotificationService, TicketService, NzModalService] + }, + { + provide: TRASH_FOLDER_ID_TOKEN, + useValue: '~Trash' + } + ], + bootstrap: [AppComponent] +}) +export class AppModule {} diff --git a/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts b/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts new file mode 100644 index 00000000000..fb1e6208e78 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts @@ -0,0 +1,65 @@ +/* + * 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. + */ + +export function copyTextToClipboard(text: string): void { + const textArea: HTMLTextAreaElement = document.createElement('textarea'); + + // + // *** This styling is an extra step which is likely not required. *** + // + // Why is it here? To ensure: + // 1. the element is able to have focus and selection. + // 2. if element was to flash render it has minimal visual impact. + // 3. less flakyness with selection and copying which **might** occur if + // the textarea element is not visible. + // + // The likelihood is the element won't even render, not even a flash, + // so some of these are just precautions. However in IE the element + // is visible whilst the popup box asking the user for permission for + // the web page to copy to the clipboard. + // + + // Place in top-left corner of screen regardless of scroll position. + textArea.style.position = 'fixed'; + textArea.style.top = '0'; + textArea.style.left = '0'; + + // Ensure it has a small width and height. Setting to 1px / 1em + // doesn't work as this gives a negative w/h on some browsers. + textArea.style.width = '2em'; + textArea.style.height = '2em'; + + // We don't need padding, reducing the size if it does flash render. + textArea.style.padding = '0'; + + // Clean up any borders. + textArea.style.border = 'none'; + textArea.style.outline = 'none'; + textArea.style.boxShadow = 'none'; + + // Avoid flash of white box if rendered for any reason. + textArea.style.background = 'transparent'; + + textArea.value = text; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + } catch (err) { + window.prompt('Copy to clipboard: Ctrl+C, Enter', text); + } + + document.body.removeChild(textArea); +} diff --git a/zeppelin-web-angular/src/app/core/copy-text/index.ts b/zeppelin-web-angular/src/app/core/copy-text/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/copy-text/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/copy-text/public-api.ts b/zeppelin-web-angular/src/app/core/copy-text/public-api.ts new file mode 100644 index 00000000000..aa47aad6726 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/copy-text/public-api.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './copy-text-to-clipboard'; diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts new file mode 100644 index 00000000000..7f394c0c4c9 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts @@ -0,0 +1,23 @@ +/* + * 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 { OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; + +export class DestroyHookComponent implements OnDestroy { + readonly destroy$ = new Subject(); + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/index.ts b/zeppelin-web-angular/src/app/core/destroy-hook/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/destroy-hook/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts b/zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts new file mode 100644 index 00000000000..c4b93aa16d8 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/destroy-hook/public-api.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './destroy-hook.component'; diff --git a/zeppelin-web-angular/src/app/core/index.ts b/zeppelin-web-angular/src/app/core/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/message-listener/index.ts b/zeppelin-web-angular/src/app/core/message-listener/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/message-listener/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts new file mode 100644 index 00000000000..5c29be8aaa0 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts @@ -0,0 +1,59 @@ +/* + * 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 { OnDestroy } from '@angular/core'; +import { Subscriber } from 'rxjs'; + +import { MessageReceiveDataTypeMap, ReceiveArgumentsType } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services'; + +export class MessageListenersManager implements OnDestroy { + __zeppelinMessageListeners__: Array<() => void>; + __zeppelinMessageListeners$__ = new Subscriber(); + constructor(public messageService: MessageService) { + if (this.__zeppelinMessageListeners__) { + this.__zeppelinMessageListeners__.forEach(fn => fn.apply(this)); + } + } + + ngOnDestroy(): void { + this.__zeppelinMessageListeners$__.unsubscribe(); + this.__zeppelinMessageListeners$__ = null; + } +} + +export function MessageListener(op: K) { + return function( + target: MessageListenersManager, + propertyKey: string, + descriptor: TypedPropertyDescriptor> + ) { + const oldValue = descriptor.value as ReceiveArgumentsType; + + const fn = function() { + // tslint:disable:no-invalid-this + this.__zeppelinMessageListeners$__.add( + this.messageService.receive(op).subscribe(data => { + oldValue.apply(this, [data]); + }) + ); + }; + + if (!target.__zeppelinMessageListeners__) { + target.__zeppelinMessageListeners__ = [fn]; + } else { + target.__zeppelinMessageListeners__.push(fn); + } + + return descriptor; + }; +} diff --git a/zeppelin-web-angular/src/app/core/message-listener/public-api.ts b/zeppelin-web-angular/src/app/core/message-listener/public-api.ts new file mode 100644 index 00000000000..61a92db9183 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/message-listener/public-api.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './message-listener'; diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/public-api.ts new file mode 100644 index 00000000000..c5141035cc3 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/public-api.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export * from './message-listener'; +export * from './destroy-hook'; +export * from './copy-text'; diff --git a/zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts b/zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts new file mode 100644 index 00000000000..940a29249fc --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/helium-manager.module.ts @@ -0,0 +1,27 @@ +/* + * 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 { Compiler, CompilerFactory, COMPILER_OPTIONS, NgModule } from '@angular/core'; +import { JitCompilerFactory } from '@angular/platform-browser-dynamic'; + +export function createCompiler(compilerFactory: CompilerFactory) { + return compilerFactory.createCompiler(); +} + +@NgModule({ + providers: [ + { provide: COMPILER_OPTIONS, useValue: {}, multi: true }, + { provide: CompilerFactory, useClass: JitCompilerFactory, deps: [COMPILER_OPTIONS] }, + { provide: Compiler, useFactory: createCompiler, deps: [CompilerFactory] } + ] +}) +export class HeliumManagerModule {} diff --git a/zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts b/zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts new file mode 100644 index 00000000000..1a1a03c55c3 --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/helium-manager.service.ts @@ -0,0 +1,75 @@ +/* + * 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 { Compiler, Injectable, Injector, NgModuleFactory, OnDestroy, Type } from '@angular/core'; +import { ZeppelinHeliumPackage, ZeppelinHeliumService } from '@zeppelin/helium'; +import { of, BehaviorSubject } from 'rxjs'; +import { HeliumManagerModule } from './helium-manager.module'; + +export interface CompiledPackage { + // tslint:disable-next-line:no-any + moduleFactory: NgModuleFactory; + // tslint:disable-next-line:no-any + component: Type; + injector?: Injector; + name: string; + _raw: ZeppelinHeliumPackage; +} + +@Injectable({ + providedIn: HeliumManagerModule +}) +export class HeliumManagerService implements OnDestroy { + private packages$ = new BehaviorSubject([]); + + constructor(private zeppelinHeliumService: ZeppelinHeliumService, private compiler: Compiler) {} + + initPackages() { + this.getEnabledPackages().subscribe(packages => { + packages.forEach(name => { + this.zeppelinHeliumService.loadPackage(name).then(heliumPackage => { + const loaded = this.packages$.value; + if (!loaded.find(p => p.name === heliumPackage.name)) { + this.compilePackage(heliumPackage); + } + }); + }); + }); + } + + getEnabledPackages() { + // return of(['helium-vis-example']); + return of([]); + } + + packagesLoadChange() { + return this.packages$.asObservable(); + } + + compilePackage(pack: ZeppelinHeliumPackage) { + this.compiler.compileModuleAsync(pack.module).then(moduleFactory => { + this.packages$.next([ + ...this.packages$.value, + { + moduleFactory, + name: pack.name, + component: pack.component, + _raw: pack + } + ]); + }); + } + + ngOnDestroy(): void { + this.packages$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/helium-manager/index.ts b/zeppelin-web-angular/src/app/helium-manager/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/helium-manager/public-api.ts b/zeppelin-web-angular/src/app/helium-manager/public-api.ts new file mode 100644 index 00000000000..8ba1a21026a --- /dev/null +++ b/zeppelin-web-angular/src/app/helium-manager/public-api.ts @@ -0,0 +1,14 @@ +/* + * 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. + */ + +export * from './helium-manager.service'; +export * from './helium-manager.module'; diff --git a/zeppelin-web-angular/src/app/interfaces/index.ts b/zeppelin-web-angular/src/app/interfaces/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/interfaces/interpreter.ts b/zeppelin-web-angular/src/app/interfaces/interpreter.ts new file mode 100644 index 00000000000..2e1d661d678 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/interpreter.ts @@ -0,0 +1,104 @@ +/* + * 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. + */ + +export type InterpreterPropertyTypes = 'textarea' | 'string' | 'number' | 'url' | 'password' | 'checkbox'; + +export interface Interpreter { + id: string; + name: string; + group: string; + properties: Properties; + status: string; + errorReason?: string; + interpreterGroup: InterpreterGroupItem[]; + dependencies: DependenciesItem[]; + option: Option; +} + +export interface InterpreterMap { + [key: string]: Interpreter; +} + +export interface CreateInterpreterRepositoryForm { + id: string; + url: string; + snapshot: boolean; + username: string; + password: string; + proxyProtocol: string; + proxyHost: string; + proxyPort: string; + proxyLogin: string; + proxyPassword: string; +} + +export interface InterpreterRepository { + id: string; + type: string; + url: string; + releasePolicy: ReleasePolicy; + snapshotPolicy: SnapshotPolicy; + // tslint:disable-next-line + mirroredRepositories: any[]; + repositoryManager: boolean; +} +interface ReleasePolicy { + enabled: boolean; + updatePolicy: string; + checksumPolicy: string; +} +interface SnapshotPolicy { + enabled: boolean; + updatePolicy: string; + checksumPolicy: string; +} + +interface Properties { + [key: string]: { + name: string; + value: boolean; + type: string; + defaultValue?: string; + description?: string; + }; +} + +interface InterpreterGroupItem { + name: string; + class: string; + defaultInterpreter: boolean; + editor: Editor; +} +interface Editor { + language: string; + editOnDblClick: boolean; + completionKey?: string; + completionSupport?: boolean; +} + +interface DependenciesItem { + groupArtifactVersion: string; + local: boolean; + exclusions: string[]; +} + +interface Option { + remote: boolean; + port: number; + isExistingProcess: boolean; + setPermission: boolean; + // tslint:disable-next-line:no-any + owners: any[]; + isUserImpersonate: boolean; + perNote?: string; + perUser?: string; +} diff --git a/zeppelin-web-angular/src/app/interfaces/message-interceptor.ts b/zeppelin-web-angular/src/app/interfaces/message-interceptor.ts new file mode 100644 index 00000000000..85618dfa44a --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/message-interceptor.ts @@ -0,0 +1,20 @@ +/* + * 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 { InjectionToken } from '@angular/core'; +import { MessageReceiveDataTypeMap, WebSocketMessage } from '@zeppelin/sdk'; + +export interface MessageInterceptor { + received(data: WebSocketMessage): WebSocketMessage; +} + +export const MESSAGE_INTERCEPTOR = new InjectionToken('MESSAGE_INTERCEPTOR'); diff --git a/zeppelin-web-angular/src/app/interfaces/node-list.ts b/zeppelin-web-angular/src/app/interfaces/node-list.ts new file mode 100644 index 00000000000..3330e03aa75 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/node-list.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +export interface NodeList { + root: RootNode; + flatList: FlatListNodeItem[]; + flatFolderMap: FlatFolderNodeMap; +} + +export interface RootNode { + children: NodeItem[]; +} + +export interface NodeItem { + id: string; + title: string; + isLeaf?: boolean; + expanded?: boolean; + children?: NodeItem[]; + isTrash: boolean; + path?: string; +} + +interface FlatListNodeItem { + id: string; + path: string; + isTrash: boolean; +} + +interface FlatFolderNodeMap { + [title: string]: NodeItem; +} diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/public-api.ts new file mode 100644 index 00000000000..1e07b8e496a --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './ticket'; +export * from './trash-folder-id'; +export * from './interpreter'; +export * from './message-interceptor'; +export * from './security'; diff --git a/zeppelin-web-angular/src/app/interfaces/security.ts b/zeppelin-web-angular/src/app/interfaces/security.ts new file mode 100644 index 00000000000..ff7db2a97d2 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/security.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export interface SecurityUserList { + roles: string[]; + users: string[]; +} + +export interface Permissions { + readers: string[]; + owners: string[]; + writers: string[]; + runners: string[]; +} diff --git a/zeppelin-web-angular/src/app/interfaces/ticket.ts b/zeppelin-web-angular/src/app/interfaces/ticket.ts new file mode 100644 index 00000000000..0f4883e0d2b --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/ticket.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +export class ITicket { + principal = ''; + ticket = ''; + redirectURL = ''; + roles = ''; +} + +export class IZeppelinVersion { + 'git-commit-id': string; + 'git-timestamp': string; + 'version': string; +} + +export class ITicketWrapped extends ITicket { + init = false; + screenUsername = ''; +} diff --git a/zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts b/zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts new file mode 100644 index 00000000000..035b92a1789 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/trash-folder-id.ts @@ -0,0 +1,15 @@ +/* + * 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 { InjectionToken } from '@angular/core'; + +export const TRASH_FOLDER_ID_TOKEN = new InjectionToken('TRASH_FOLDER_ID'); diff --git a/zeppelin-web-angular/src/app/languages/index.ts b/zeppelin-web-angular/src/app/languages/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/languages/load.ts b/zeppelin-web-angular/src/app/languages/load.ts new file mode 100644 index 00000000000..5dad459c888 --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/load.ts @@ -0,0 +1,20 @@ +/* + * 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 { languages } from 'monaco-editor'; +import { conf as ScalaConf, language as ScalaLanguage } from './scala'; + +export const loadMonacoLanguage = () => { + languages.register({ id: 'scala' }); + languages.setMonarchTokensProvider('scala', ScalaLanguage); + languages.setLanguageConfiguration('scala', ScalaConf); +}; diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts b/zeppelin-web-angular/src/app/languages/public-api.ts new file mode 100644 index 00000000000..973c93158ba --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/public-api.ts @@ -0,0 +1,14 @@ +/* + * 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. + */ + +export * from './scala'; +export * from './load'; diff --git a/zeppelin-web-angular/src/app/languages/scala.ts b/zeppelin-web-angular/src/app/languages/scala.ts new file mode 100644 index 00000000000..581049129e0 --- /dev/null +++ b/zeppelin-web-angular/src/app/languages/scala.ts @@ -0,0 +1,236 @@ +/* + * 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. + */ + +'use strict'; + +import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration; +import ILanguage = monaco.languages.IMonarchLanguage; + +export const conf: IRichLanguageConfiguration = { + // the default separators except `@$` + wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g, + comments: { + lineComment: '//', + blockComment: ['/*', '*/'] + }, + brackets: [['{', '}'], ['[', ']'], ['(', ')']], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" } + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '<', close: '>' } + ] +}; + +export const language = { + defaultToken: '', + tokenPostfix: '.scala', + + keywords: [ + // From https://www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html + 'abstract', + 'case', + 'catch', + 'class', + 'def', + 'do', + 'else', + 'extends', + 'false', + 'final', + 'finally', + 'for', + 'forSome', + 'if', + 'implicit', + 'import', + 'lazy', + 'macro', + 'match', + 'new', + 'null', + 'object', + 'override', + 'package', + 'private', + 'protected', + 'return', + 'sealed', + 'super', + 'this', + 'throw', + 'trait', + 'try', + 'true', + 'type', + 'val', + 'var', + 'while', + 'with', + 'yield' + ], + + operators: [ + '_', + ':', + '=', + '=>', + '<-', + '<:', + '<%', + '>:', + '#', + '@', + + // Copied from java.ts, to be validated + '=', + '>', + '<', + '!', + '~', + '?', + ':', + '==', + '<=', + '>=', + '!=', + '&&', + '||', + '++', + '--', + '+', + '-', + '*', + '/', + '&', + '|', + '^', + '%', + '<<', + '>>', + '>>>', + '+=', + '-=', + '*=', + '/=', + '&=', + '|=', + '^=', + '%=', + '<<=', + '>>=', + '>>>=' + ], + + // we include these common regular expressions + symbols: /[=>](?!@symbols)/, '@brackets'], + [ + /@symbols/, + { + cases: { + '@operators': 'delimiter', + '@default': '' + } + } + ], + + // @ annotations. + [/@\s*[a-zA-Z_\$][\w\$]*/, 'annotation'], + + // numbers + [/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/, 'number.float'], + [/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/, 'number.float'], + [/0[xX](@hexdigits)[Ll]?/, 'number.hex'], + [/0(@octaldigits)[Ll]?/, 'number.octal'], + [/0[bB](@binarydigits)[Ll]?/, 'number.binary'], + [/(@digits)[fFdD]/, 'number.float'], + [/(@digits)[lL]?/, 'number'], + + // delimiter: after number because of .\d floats + [/[;,.]/, 'delimiter'], + + // strings + [/"([^"\\]|\\.)*$/, 'string.invalid'], // non-teminated string + [/"/, 'string', '@string'], + + // characters + [/'[^\\']'/, 'string'], + [/(')(@escapes)(')/, ['string', 'string.escape', 'string']], + [/'/, 'string.invalid'] + ], + + whitespace: [ + [/[ \t\r\n]+/, ''], + [/\/\*\*(?!\/)/, 'comment.doc', '@scaladoc'], + [/\/\*/, 'comment', '@comment'], + [/\/\/.*$/, 'comment'] + ], + + comment: [ + [/[^\/*]+/, 'comment'], + // [/\/\*/, 'comment', '@push' ], // nested comment not allowed :-( + // [/\/\*/, 'comment.invalid' ], // this breaks block comments in the shape of /* //*/ + [/\*\//, 'comment', '@pop'], + [/[\/*]/, 'comment'] + ], + // Identical copy of comment above, except for the addition of .doc + scaladoc: [ + [/[^\/*]+/, 'comment.doc'], + // [/\/\*/, 'comment.doc', '@push' ], // nested comment not allowed :-( + [/\/\*/, 'comment.doc.invalid'], + [/\*\//, 'comment.doc', '@pop'], + [/[\/*]/, 'comment.doc'] + ], + + string: [ + [/[^\\"]+/, 'string'], + [/@escapes/, 'string.escape'], + [/\\./, 'string.escape.invalid'], + [/"/, 'string', '@pop'] + ] + } +} as ILanguage; diff --git a/zeppelin-web-angular/src/app/pages/login/login-routing.module.ts b/zeppelin-web-angular/src/app/pages/login/login-routing.module.ts new file mode 100644 index 00000000000..06dd0304db8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login-routing.module.ts @@ -0,0 +1,29 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { LoginComponent } from './login.component'; + +const routes: Routes = [ + { + path: '', + component: LoginComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class LoginRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/login/login.component.html b/zeppelin-web-angular/src/app/pages/login/login.component.html new file mode 100644 index 00000000000..faa16b67189 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.component.html @@ -0,0 +1,46 @@ + + +

diff --git a/zeppelin-web-angular/src/app/pages/login/login.component.less b/zeppelin-web-angular/src/app/pages/login/login.component.less new file mode 100644 index 00000000000..7aac210300d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.component.less @@ -0,0 +1,69 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + .content { + height: 100vh; + width: 100vw; + + &:after { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url("../../../assets/images/bg.jpg"); + background-size: cover; + filter: blur(4px); + background-repeat: no-repeat; + background-position: center; + } + + .inner { + width: 800px; + height: 300px; + position: absolute; + z-index: 1; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + box-shadow: @box-shadow-base; + + .form { + width: 500px; + position: absolute; + left: 0; + height: 100%; + background: @component-background; + padding: 36px; + } + + .sidebar { + width: 300px; + position: absolute; + right: 0; + height: 100%; + background: @primary-color; + padding: 24px 36px; + color: @text-color-dark; + + h1 { + color: @heading-color-dark; + } + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/login/login.component.ts b/zeppelin-web-angular/src/app/pages/login/login.component.ts new file mode 100644 index 00000000000..937724974b6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.component.ts @@ -0,0 +1,47 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; + +import { TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class LoginComponent implements OnInit { + userName: string; + password: string; + loading = false; + + login() { + this.loading = true; + this.ticketService.login(this.userName, this.password).subscribe( + () => { + this.loading = false; + this.cdr.markForCheck(); + this.router.navigate(['/']).then(); + }, + () => { + this.loading = false; + this.cdr.markForCheck(); + } + ); + } + + constructor(private ticketService: TicketService, private cdr: ChangeDetectorRef, private router: Router) {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/login/login.module.ts b/zeppelin-web-angular/src/app/pages/login/login.module.ts new file mode 100644 index 00000000000..46f40a055d5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/login/login.module.ts @@ -0,0 +1,26 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NzButtonModule, NzFormModule, NzIconModule, NzInputModule } from 'ng-zorro-antd'; + +import { LoginRoutingModule } from './login-routing.module'; +import { LoginComponent } from './login.component'; + +@NgModule({ + declarations: [LoginComponent], + imports: [CommonModule, LoginRoutingModule, FormsModule, NzFormModule, NzInputModule, NzButtonModule, NzIconModule] +}) +export class LoginModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts new file mode 100644 index 00000000000..23a345f025a --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home-routing.module.ts @@ -0,0 +1,29 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { HomeComponent } from './home.component'; + +const routes: Routes = [ + { + path: '', + component: HomeComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class HomeRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html new file mode 100644 index 00000000000..5a26044c970 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html @@ -0,0 +1,41 @@ + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.less b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.less new file mode 100644 index 00000000000..3f79862ddc6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.less @@ -0,0 +1,37 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .content { + margin: 12px; + border: 1px solid @border-color-base; + padding: 24px; + background-color: @component-background; + position: relative; + background-image: url(../../../../assets/images/zeppelin_svg_logo_bg.svg); + background-repeat: no-repeat; + background-position: right bottom; + } + .welcome { + margin-bottom: 12px; + } + .more-info { + h3 { + margin-top: 0.5em; + } + } + .refresh-note { + margin-left: 6px + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts new file mode 100644 index 00000000000..ecc40995d68 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts @@ -0,0 +1,48 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { OP } from '@zeppelin/sdk'; +import { MessageService, TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-home', + templateUrl: './home.component.html', + styleUrls: ['./home.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class HomeComponent extends MessageListenersManager implements OnInit { + loading = false; + + reloadNoteList() { + this.messageService.reloadAllNotesFromRepo(); + this.loading = true; + } + + @MessageListener(OP.NOTES_INFO) + getNotes() { + this.loading = false; + this.cdr.markForCheck(); + } + + constructor( + public ticketService: TicketService, + public messageService: MessageService, + private cdr: ChangeDetectorRef + ) { + super(messageService); + } + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts new file mode 100644 index 00000000000..24e59a71853 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts @@ -0,0 +1,27 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { NzGridModule, NzIconModule, NzToolTipModule } from 'ng-zorro-antd'; + +import { ShareModule } from '@zeppelin/share'; + +import { HomeRoutingModule } from './home-routing.module'; +import { HomeComponent } from './home.component'; + +@NgModule({ + declarations: [HomeComponent], + imports: [CommonModule, HomeRoutingModule, NzGridModule, NzIconModule, NzToolTipModule, ShareModule] +}) +export class HomeModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html new file mode 100644 index 00000000000..57a0b6339d7 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.html @@ -0,0 +1,158 @@ + + +
+ + + ID + + + + + + + + URL + + + + + + + + + + + + + + + + + Snapshot + + + + + + + + Username + + + + + + + + Password + + + + + + + + + Protocol + + + + + + + + + + + Host + + + + + + + + Port + + + + + + + + Login + + + + + + + + Password + + + + + +
+ + diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less new file mode 100644 index 00000000000..f348ef32466 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.less @@ -0,0 +1,19 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + nz-form-item { + margin-bottom: 5px; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts new file mode 100644 index 00000000000..8dd38c97766 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts @@ -0,0 +1,78 @@ +/* + * 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 { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { takeUntil } from 'rxjs/operators'; + +import { NzModalRef } from 'ng-zorro-antd'; + +import { DestroyHookComponent } from '@zeppelin/core'; +import { CreateInterpreterRepositoryForm } from '@zeppelin/interfaces'; +import { InterpreterService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-interpreter-create-repository-modal', + templateUrl: './create-repository-modal.component.html', + styleUrls: ['./create-repository-modal.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class InterpreterCreateRepositoryModalComponent extends DestroyHookComponent implements OnInit { + validateForm: FormGroup; + submitting = false; + urlProtocol = 'http://'; + + handleCancel() { + this.nzModalRef.close(); + } + + handleSubmit() { + const data = this.validateForm.getRawValue() as CreateInterpreterRepositoryForm; + // set url protocol + data.url = `${this.urlProtocol}${data.url}`; + // reset proxy port + const proxyPort = Number.parseInt(data.proxyPort, 10); + data.proxyPort = Number.isNaN(proxyPort) ? null : `${proxyPort}`; + this.interpreterService + .addRepository(data) + .pipe(takeUntil(this.destroy$)) + .subscribe(() => { + this.nzModalRef.close('Done'); + }); + } + + constructor( + private formBuilder: FormBuilder, + private nzModalRef: NzModalRef, + private interpreterService: InterpreterService + ) { + super(); + } + + ngOnInit() { + this.validateForm = this.formBuilder.group({ + id: ['', [Validators.required]], + url: ['', [Validators.required]], + snapshot: [false, [Validators.required]], + username: '', + password: '', + proxyProtocol: 'HTTP', + proxyHost: '', + proxyPort: [ + null, + [Validators.pattern('^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$')] + ], + proxyLogin: '', + proxyPassword: '' + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts new file mode 100644 index 00000000000..c9c995825cb --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter-routing.module.ts @@ -0,0 +1,29 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { InterpreterComponent } from './interpreter.component'; + +const routes: Routes = [ + { + path: '', + component: InterpreterComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class InterpreterRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html new file mode 100644 index 00000000000..144a57d2fca --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html @@ -0,0 +1,66 @@ + + + + + + + + + + +
+ +

Repositories

+

Available repository lists. These repositories are used to resolve external dependencies of interpreter.

+ + {{repo.id}} + + + + +
+
+
+ + + Create + + + + + +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less new file mode 100644 index 00000000000..8d5f88d6044 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less @@ -0,0 +1,51 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .search-input { + width: 256px; + } + + @media (max-width:959px){ + .search-input { + width: 100%; + } + } + + nz-tag.repo-item { + border-color: transparent; + background: @primary-6; + color: @text-color-inverse; + ::ng-deep i.anticon-close { + color: @text-color-inverse; + &:hover { + color: @icon-color-hover; + } + } + } + + .editable-tag { + background: @white; + border-style: dashed; + } + + .content { + padding: @card-padding-base / 2; + + .create-interpreter { + text-align: center; + margin-bottom: 10px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts new file mode 100644 index 00000000000..8e216282d19 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts @@ -0,0 +1,186 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { debounceTime } from 'rxjs/operators'; + +import { collapseMotion, NzMessageService, NzModalService } from 'ng-zorro-antd'; + +import { Interpreter, InterpreterPropertyTypes, InterpreterRepository } from '@zeppelin/interfaces'; +import { InterpreterService } from '@zeppelin/services'; + +import { InterpreterCreateRepositoryModalComponent } from './create-repository-modal/create-repository-modal.component'; + +@Component({ + selector: 'zeppelin-interpreter', + templateUrl: './interpreter.component.html', + styleUrls: ['./interpreter.component.less'], + animations: [collapseMotion], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class InterpreterComponent implements OnInit, OnDestroy { + searchInterpreter = ''; + search$ = new Subject(); + showRepository = false; + showCreateSetting = false; + propertyTypes: InterpreterPropertyTypes[] = []; + interpreterSettings: Interpreter[] = []; + repositories: InterpreterRepository[] = []; + availableInterpreters: Interpreter[] = []; + filteredInterpreterSettings: Interpreter[] = []; + + onSearchChange(value: string) { + this.search$.next(value); + } + + filterInterpreters(value: string) { + this.filteredInterpreterSettings = this.interpreterSettings.filter(e => e.name.search(value) !== -1); + this.cdr.markForCheck(); + } + + triggerRepository(): void { + this.showRepository = !this.showRepository; + this.cdr.markForCheck(); + } + + removeRepository(repo: InterpreterRepository): void { + this.nzModalService.confirm({ + nzTitle: repo.id, + nzContent: 'Do you want to delete this repository?', + nzOnOk: () => { + this.interpreterService.removeRepository(repo.id).subscribe(() => { + this.repositories = this.repositories.filter(e => e.id !== repo.id); + this.cdr.markForCheck(); + }); + } + }); + } + + addInterpreterSetting(data: Interpreter): void { + this.interpreterService.addInterpreterSetting(data).subscribe(res => { + this.interpreterSettings.push(res); + this.showCreateSetting = false; + this.filterInterpreters(this.searchInterpreter); + this.cdr.markForCheck(); + }); + } + + updateInterpreter(data: Interpreter): void { + this.interpreterService.updateInterpreter(data).subscribe(res => { + const current = this.interpreterSettings.find(e => e.name === res.name); + if (current) { + current.status = res.status; + current.errorReason = res.errorReason; + current.option = res.option; + current.properties = res.properties; + current.dependencies = res.dependencies; + } + this.filterInterpreters(this.searchInterpreter); + this.cdr.markForCheck(); + }); + } + + removeInterpreterSetting(settingId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Remove Interpreter', + nzContent: 'Do you want to delete this interpreter setting?', + nzOnOk: () => { + this.interpreterService.removeInterpreterSetting(settingId).subscribe(() => { + const index = this.interpreterSettings.findIndex(e => e.name === settingId); + this.interpreterSettings.splice(index, 1); + this.filterInterpreters(this.searchInterpreter); + this.cdr.markForCheck(); + }); + } + }); + } + + restartInterpreterSetting(settingId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Restart Interpreter', + nzContent: 'Do you want to restart this interpreter?', + nzOnOk: () => { + this.interpreterService.restartInterpreterSetting(settingId).subscribe(() => { + this.nzMessageService.info('Interpreter stopped. Will be lazily started on next run.'); + }); + } + }); + } + + createRepository(): void { + const modalRef = this.nzModalService.create({ + nzTitle: 'Add New Repository', + nzContent: InterpreterCreateRepositoryModalComponent, + nzFooter: null, + nzWidth: '600px' + }); + modalRef.afterClose.subscribe(data => { + if (data === 'Done') { + this.getRepositories(); + } + }); + } + + getPropertyTypes(): void { + this.interpreterService.getAvailableInterpreterPropertyTypes().subscribe(data => { + this.propertyTypes = data; + this.cdr.markForCheck(); + }); + } + + getInterpreterSettings(): void { + this.interpreterService.getInterpretersSetting().subscribe(data => { + this.interpreterSettings = data; + this.filteredInterpreterSettings = data; + this.cdr.markForCheck(); + }); + } + + getAvailableInterpreters(): void { + this.interpreterService.getAvailableInterpreters().subscribe(data => { + this.availableInterpreters = Object.keys(data) + .sort() + .map(key => data[key]); + this.cdr.markForCheck(); + }); + } + + getRepositories(): void { + this.interpreterService.getRepositories().subscribe(data => { + this.repositories = data; + this.cdr.markForCheck(); + }); + } + + constructor( + private interpreterService: InterpreterService, + private cdr: ChangeDetectorRef, + private nzModalService: NzModalService, + private nzMessageService: NzMessageService + ) {} + + ngOnInit() { + this.getPropertyTypes(); + this.getInterpreterSettings(); + this.getAvailableInterpreters(); + this.getRepositories(); + + this.search$.pipe(debounceTime(150)).subscribe(value => this.filterInterpreters(value)); + } + + ngOnDestroy(): void { + this.search$.next(); + this.search$.complete(); + this.search$ = null; + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts new file mode 100644 index 00000000000..37a9a0e10a1 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts @@ -0,0 +1,73 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { + NzAlertModule, + NzBadgeModule, + NzButtonModule, + NzCardModule, + NzCheckboxModule, + NzDividerModule, + NzDropDownModule, + NzFormModule, + NzIconModule, + NzInputModule, + NzMessageModule, + NzModalModule, + NzRadioModule, + NzSelectModule, + NzSwitchModule, + NzTableModule, + NzTagModule, + NzToolTipModule +} from 'ng-zorro-antd'; + +import { ShareModule } from '@zeppelin/share'; + +import { InterpreterCreateRepositoryModalComponent } from './create-repository-modal/create-repository-modal.component'; +import { InterpreterRoutingModule } from './interpreter-routing.module'; +import { InterpreterComponent } from './interpreter.component'; +import { InterpreterItemComponent } from './item/item.component'; + +@NgModule({ + declarations: [InterpreterComponent, InterpreterCreateRepositoryModalComponent, InterpreterItemComponent], + entryComponents: [InterpreterCreateRepositoryModalComponent], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + InterpreterRoutingModule, + ShareModule, + NzFormModule, + NzSelectModule, + NzSwitchModule, + NzToolTipModule, + NzCheckboxModule, + NzRadioModule, + NzBadgeModule, + NzButtonModule, + NzModalModule, + NzInputModule, + NzDividerModule, + NzTagModule, + NzCardModule, + NzDropDownModule, + NzIconModule, + NzTableModule, + NzMessageModule, + NzAlertModule + ] +}) +export class InterpreterModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html new file mode 100644 index 00000000000..2e4e374520b --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html @@ -0,0 +1,447 @@ + + + + +
+

+ {{ interpreter.name }} + + , %{{ interpreter.name }}.{{ item.name }} + %{{ interpreter.name }} + + + + + + +

+
+
+ + + + + +
+ + + +
+
+ + +

Create new interpreter

+
+ + Interpreter Name + + + + {{ formGroup.get('name')?.errors?.message }} + + + + + Interpreter group + + + + + + +
+
+

Option

+

+ + + + The interpreter will be instantiated + + {{ interpreterRunningOption }} + + + + +

+ + in + + + {{ optionFormGroup.get('perUser').value }} + + + + {{ optionFormGroup.get('perNote').value }} + + + + + + + + {{ optionFormGroup.get('perUser').value }} + + + + {{ optionFormGroup.get('perNote').value }} + + + + + + + process + + and Per Note in + + {{ optionFormGroup.get('perNote').value }} + + + + + + process + + . + + + + + + +

+
+ + + + + + + + + + + + + + + Host + + + + + + Port + + + + + + + + + + + + + + + Owners + + + + + + Enter comma separated users and groups in the fields. Empty field (*) implies anyone can run this + interpreter. + + + + +
+ + +

Properties

+
+ + + + Name + Value + Description + Action + + + + + {{ control.get('key').value }} + + + + + + + + + + + + ****** + + {{control.get('value').value}} + + {{ control.get('value').value }} + + + + {{ control.get('description').value }} + + + + + + + + + +
+ + + + + + + + + + + +
+ + N/A + + + + + + +
+
+
+ + +

Dependencies

+
+ + + + Artifact + Exclude + Action + + + + + + + + + + + + + + + + + {{ control.get('groupArtifactVersion').value }} + {{ control.get('exclusions').value }} + + + + + + + + + + + + + + + +
+
+ + +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less new file mode 100644 index 00000000000..856506e92f2 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less @@ -0,0 +1,105 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + display: block; + margin-bottom: @card-padding-base; + position: relative; + + ::ng-deep .interpreter-item { + &.edit { + background: @orange-1; + } + .ant-card-body { + margin-top: -@card-padding-base; + } + } + + .error-alter { + margin-top: @card-padding-base; + } + + .interpreter-status { + margin-left: 5px; + } + + .card-title { + display: inline-block; + h3 { + color: @primary-color; + margin-bottom: 0; + font-size: 1.4em; + .interpreter-group-item { + font-size: 60%; + font-weight: 400; + color: @text-color-secondary; + } + } + } + + h3.form-title { + margin: @card-padding-base 0; + } + + nz-form-item { + margin-bottom: 5px; + } + + form td textarea.ant-input { + margin-bottom: 0; + resize: none; + } + + .interpreter-form, .option-form { + input, nz-select { + width: 256px; + } + @media (max-width:959px){ + input, nz-select { + width: 100%; + } + } + } + + .edit-properties-value { + display: flex; + align-items: center; + + .value-input { + flex: 1; + } + + .type-selector { + width: 150px; + margin-left: 5px; + } + } + + .extra-wrap { + button + button { + margin-bottom: 0; + margin-left: 8px; + } + } + + .item-footer { + padding: 24px 0px 12px 0px; + text-align: right; + button + button { + margin-bottom: 0; + margin-left: 8px; + } + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts new file mode 100644 index 00000000000..fb9fb0097d1 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts @@ -0,0 +1,405 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { AbstractControl, FormArray, FormBuilder, FormGroup, ValidationErrors, Validators } from '@angular/forms'; +import { DestroyHookComponent } from '@zeppelin/core'; +import { Interpreter } from '@zeppelin/interfaces'; +import { InterpreterService, SecurityService, TicketService } from '@zeppelin/services'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; +import { InterpreterComponent } from '../interpreter.component'; + +@Component({ + selector: 'zeppelin-interpreter-item', + templateUrl: './item.component.html', + styleUrls: ['./item.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class InterpreterItemComponent extends DestroyHookComponent implements OnInit, OnDestroy { + @Input() mode: 'create' | 'view' | 'edit' = 'view'; + @Input() interpreter: Interpreter; + + formGroup: FormGroup; + optionFormGroup: FormGroup; + editingPropertiesFormGroup: FormGroup; + editingDependenceFormGroup: FormGroup; + propertiesFormArray: FormArray; + dependenciesFormArray: FormArray; + userList$: Observable; + userSearchChange$ = new BehaviorSubject(''); + runningOptionMap = { + sharedModeName: 'shared', + globallyModeName: 'Globally', + perNoteModeName: 'Per Note', + perUserModeName: 'Per User' + }; + + sessionOptionMap = { + isolated: 'isolated', + scoped: 'scoped', + shared: 'shared' + }; + + interpreterRunningOption = 'Globally'; + + switchToEditMode(): void { + this.setupEditableForm(); + this.formGroup.enable(); + this.mode = 'edit'; + this.cdr.markForCheck(); + } + + handleRestart() { + this.parent.restartInterpreterSetting(this.interpreter.name); + } + + handleRemove() { + this.parent.removeInterpreterSetting(this.interpreter.name); + } + + handleSave() { + const formData = this.formGroup.getRawValue(); + const properties = {}; + + formData.properties + .sort(e => e.key) + .forEach(e => { + const { key, value, type } = e; + properties[key] = { + value, + type, + name: key + }; + }); + formData.properties = properties; + + formData.dependencies.forEach(e => { + e.exclusions = e.exclusions.split(',').filter(s => s !== ''); + }); + + if (this.mode === 'create') { + this.parent.addInterpreterSetting(formData); + } else { + this.parent.updateInterpreter(formData); + this.mode = 'view'; + } + } + + handleCancel() { + if (this.mode === 'create') { + this.parent.showCreateSetting = false; + } else { + this.mode = 'view'; + this.buildForm(); + this.formGroup.disable(); + } + } + + interpretersTrackFn(_: number, item: Interpreter) { + return item.name; + } + + onUserSearch(value: string): void { + this.userSearchChange$.next(value); + } + + removeProperty(index: number): void { + this.propertiesFormArray.removeAt(index); + this.cdr.markForCheck(); + } + + removeDependence(index: number): void { + this.dependenciesFormArray.removeAt(index); + this.cdr.markForCheck(); + } + + onTypeChange(type: string) { + let valueSet: string | boolean | number; + switch (type) { + case 'number': + valueSet = 0; + break; + case 'checkbox': + valueSet = false; + break; + default: + valueSet = ''; + } + this.editingPropertiesFormGroup.get('value').setValue(valueSet); + } + + addDependence(): void { + this.editingDependenceFormGroup.updateValueAndValidity(); + if (this.editingDependenceFormGroup.valid) { + const data = this.editingDependenceFormGroup.getRawValue(); + const current = this.dependenciesFormArray.controls.find( + control => control.get('groupArtifactVersion').value === data.groupArtifactVersion + ); + if (current) { + current.get('exclusions').setValue(data.exclusions); + } else { + this.dependenciesFormArray.push( + this.formBuilder.group({ + groupArtifactVersion: [data.groupArtifactVersion, [Validators.required]], + exclusions: data.exclusions + }) + ); + } + this.editingDependenceFormGroup.reset({ + exclusions: '', + groupArtifactVersion: '' + }); + } + } + + addProperties(): void { + this.editingPropertiesFormGroup.updateValueAndValidity(); + if (this.editingPropertiesFormGroup.valid) { + const data = this.editingPropertiesFormGroup.getRawValue(); + + const current = this.propertiesFormArray.controls.find(control => control.get('key').value === data.key); + if (current) { + current.get('value').setValue(data.value); + current.get('type').setValue(data.type); + } else { + this.propertiesFormArray.push( + this.formBuilder.group({ + key: [data.key, [Validators.required]], + value: data.value || '', + description: null, + type: data.type + }) + ); + } + this.editingPropertiesFormGroup.reset({ + key: '', + value: '', + description: null, + type: 'string' + }); + } + } + + setInterpreterRunningOption(perNote: string, perUser: string) { + const { sharedModeName, globallyModeName, perNoteModeName, perUserModeName } = this.runningOptionMap; + + this.optionFormGroup.get('perNote').setValue(perNote); + this.optionFormGroup.get('perUser').setValue(perUser); + + // Globally == shared_perNote + shared_perUser + if (perNote === sharedModeName && perUser === sharedModeName) { + this.interpreterRunningOption = globallyModeName; + return; + } + + const ticket = this.ticketService.originTicket; + + if (ticket.ticket === 'anonymous' && ticket.roles === '[]') { + if (perNote !== undefined && typeof perNote === 'string' && perNote !== '') { + this.interpreterRunningOption = perNoteModeName; + return; + } + } else if (ticket.ticket !== 'anonymous') { + if (perNote !== undefined && typeof perNote === 'string' && perNote !== '') { + if (perUser !== undefined && typeof perUser === 'string' && perUser !== '') { + this.interpreterRunningOption = perUserModeName; + return; + } + this.interpreterRunningOption = perNoteModeName; + return; + } + } + + this.optionFormGroup.get('perNote').setValue(sharedModeName); + this.optionFormGroup.get('perUser').setValue(sharedModeName); + this.interpreterRunningOption = globallyModeName; + } + + setPerNoteOrUserOption(type: 'perNote' | 'perUser', value: string) { + this.optionFormGroup.get(type).setValue(value); + switch (value) { + case this.sessionOptionMap.isolated: + this.optionFormGroup.get('session').setValue(false); + this.optionFormGroup.get('process').setValue(true); + break; + case this.sessionOptionMap.scoped: + this.optionFormGroup.get('session').setValue(true); + this.optionFormGroup.get('process').setValue(false); + break; + case this.sessionOptionMap.shared: + this.optionFormGroup.get('session').setValue(false); + this.optionFormGroup.get('process').setValue(false); + break; + } + } + + nameValidator(control: AbstractControl): ValidationErrors | null { + if (this.mode !== 'create') { + return null; + } + const name = (control.value as string).trim(); + const exist = this.parent.interpreterSettings.find(e => e.name === name); + if (exist) { + return { exist: true, message: `Name '${name}' already exists` }; + } else { + return null; + } + } + + buildForm(): void { + let name = ''; + let group = ''; + this.optionFormGroup = this.formBuilder.group({ + isExistingProcess: false, + isUserImpersonate: false, + owners: [[]], + perNote: '', + perUser: '', + port: [ + null, + [Validators.pattern('^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$')] + ], + host: '', + remote: true, + setPermission: false, + session: false, + process: false + }); + + this.propertiesFormArray = this.formBuilder.array([]); + this.dependenciesFormArray = this.formBuilder.array([]); + + if (this.mode === 'view' && this.interpreter) { + name = this.interpreter.name; + group = this.interpreter.group; + + // set option fields + this.optionFormGroup.reset({ + ...this.interpreter.option, + port: this.interpreter.option.port === -1 ? null : this.interpreter.option.port + }); + + // set dependencies fields + this.interpreter.dependencies.forEach(e => { + this.dependenciesFormArray.push( + this.formBuilder.group({ + exclusions: [e.exclusions.join(',')], + groupArtifactVersion: [e.groupArtifactVersion, [Validators.required]] + }) + ); + }); + + // set properties fields + Object.keys(this.interpreter.properties).forEach(key => { + const item = this.interpreter.properties[key]; + this.propertiesFormArray.push( + this.formBuilder.group({ + key: key, + value: item.value, + description: null, + type: item.type + }) + ); + }); + } + + this.formGroup = this.formBuilder.group({ + name: [name, [Validators.required, c => this.nameValidator(c)]], + group: [group, [Validators.required]], + option: this.optionFormGroup, + properties: this.propertiesFormArray, + dependencies: this.dependenciesFormArray + }); + } + + setupEditableForm(): void { + this.userList$ = this.userSearchChange$.pipe( + debounceTime(500), + filter(value => !!value), + switchMap(value => this.securityService.searchUsers(value)), + map(data => data.users), + tap(() => { + this.cdr.markForCheck(); + }) + ); + + this.editingPropertiesFormGroup = this.formBuilder.group({ + key: ['', [Validators.required]], + value: '', + description: null, + type: 'string' + }); + + this.editingDependenceFormGroup = this.formBuilder.group({ + groupArtifactVersion: ['', [Validators.required]], + exclusions: [''] + }); + + if (this.mode === 'create') { + this.formGroup + .get('group') + .valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe(value => { + // remove all controls + while (this.propertiesFormArray.length) { + this.propertiesFormArray.removeAt(0); + } + + const interpreters = this.parent.availableInterpreters.filter(e => e.group === value); + interpreters.forEach(interpreter => { + Object.keys(interpreter.properties).forEach(key => { + this.propertiesFormArray.push( + this.formBuilder.group({ + key: [key, [Validators.required]], + value: interpreter.properties[key].defaultValue, + description: interpreter.properties[key].description, + type: interpreter.properties[key].type + }) + ); + }); + }); + this.cdr.markForCheck(); + }); + } + } + + constructor( + public parent: InterpreterComponent, + public ticketService: TicketService, + private securityService: SecurityService, + private interpreterService: InterpreterService, + private formBuilder: FormBuilder, + private cdr: ChangeDetectorRef + ) { + super(); + } + + ngOnInit() { + this.buildForm(); + const option = this.optionFormGroup.getRawValue(); + this.setInterpreterRunningOption(option.perNote, option.perUser); + + if (this.mode !== 'view') { + this.setupEditableForm(); + this.formGroup.enable(); + } else { + this.formGroup.disable(); + } + } + + ngOnDestroy(): void { + this.userSearchChange$.complete(); + this.userSearchChange$ = null; + super.ngOnDestroy(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts new file mode 100644 index 00000000000..5d12c451d5c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager-routing.module.ts @@ -0,0 +1,29 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { JobManagerComponent } from './job-manager.component'; + +const routes: Routes = [ + { + path: '', + component: JobManagerComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class JobManagerRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html new file mode 100644 index 00000000000..a5eba0e5f04 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html @@ -0,0 +1,75 @@ + + + +
+ + + + + + + + + + + + Interpreter + + + + + + + + + Sort + + + + + + + + Total + + {{ filteredJobs.length }} + + + + + + + + +
+
+
+ + + + + + + + + + +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less new file mode 100644 index 00000000000..0bdc612836a --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.less @@ -0,0 +1,50 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .header-form { + .interpreter-select { + min-width: 100px; + } + .sort-select { + min-width: 155px; + } + } + + .content { + padding: @card-padding-base / 2; + + ::ng-deep .ant-skeleton-paragraph { + margin-bottom: 0; + } + + nz-empty { + margin-top: 76px; + } + } + + @media (max-width: 1230px) { + .status-legend { + display: none; + } + } + .status-legend { + float: right; + margin-right: 0; + zeppelin-job-manager-job-status { + margin-left: 10px; + display: inline-block; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts new file mode 100644 index 00000000000..8e426fd383c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts @@ -0,0 +1,138 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; + +import { NzModalService } from 'ng-zorro-antd'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { JobsItem, JobStatus, ListNoteJobs, ListUpdateNoteJobs, OP } from '@zeppelin/sdk'; +import { JobManagerService, MessageService } from '@zeppelin/services'; + +enum JobDateSortKeys { + RECENTLY_UPDATED = 'Recently Update', + OLDEST_UPDATED = 'Oldest Updated' +} + +interface FilterForm { + noteName: string; + interpreter: string; + sortBy: string; +} + +@Component({ + selector: 'zeppelin-job-manager', + templateUrl: './job-manager.component.html', + styleUrls: ['./job-manager.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JobManagerComponent extends MessageListenersManager implements OnInit, OnDestroy { + form: FormGroup; + jobStatusKeys = Object.keys(JobStatus).map(k => JobStatus[k]); + sortKeys = Object.keys(JobDateSortKeys).map(k => JobDateSortKeys[k]); + interpreters: string[] = []; + filteredJobs: JobsItem[] = []; + filterString: string = ''; + jobs: JobsItem[] = []; + loading = true; + + @MessageListener(OP.LIST_NOTE_JOBS) + setJobs(data: ListNoteJobs) { + this.jobs = data.noteJobs.jobs.filter(j => typeof j.interpreter !== 'undefined'); + const interpreters = this.jobs.map(job => job.interpreter); + this.interpreters = Array.from(new Set(interpreters)); + this.loading = false; + this.filterJobs(); + } + + @MessageListener(OP.LIST_UPDATE_NOTE_JOBS) + updateJobs(data: ListUpdateNoteJobs) { + data.noteRunningJobs.jobs.forEach(updateJob => { + const currentJobIndex = this.jobs.findIndex(job => job.noteId === updateJob.noteId); + if (currentJobIndex === -1) { + this.jobs.push(updateJob); + } else { + if (updateJob.isRemoved) { + this.jobs.splice(currentJobIndex, 1); + } else { + this.jobs[currentJobIndex] = updateJob; + } + } + }); + this.filterJobs(); + } + + filterJobs() { + const filterData = this.form.getRawValue() as FilterForm; + this.filterString = filterData.noteName; + const isSortByAsc = filterData.sortBy === JobDateSortKeys.OLDEST_UPDATED; + this.filteredJobs = this.jobs + .filter(job => { + const escapedString = filterData.noteName.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$&'); + const noteNameReg = new RegExp(escapedString, 'gi'); + return ( + (filterData.interpreter === '*' || job.interpreter === filterData.interpreter) && + job.noteName.match(noteNameReg) + ); + }) + .sort((x, y) => (isSortByAsc ? x.unixTimeLastRun - y.unixTimeLastRun : y.unixTimeLastRun - x.unixTimeLastRun)); + this.cdr.markForCheck(); + } + + onStart(noteId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Job Dialog', + nzContent: 'Run all paragraphs?', + nzOnOk: () => { + this.jobManagerService.startJob(noteId).subscribe(); + } + }); + } + + onStop(noteId: string): void { + this.nzModalService.confirm({ + nzTitle: 'Job Dialog', + nzContent: 'Stop all paragraphs?', + nzOnOk: () => { + this.jobManagerService.stopJob(noteId).subscribe(); + } + }); + } + + constructor( + public messageService: MessageService, + private jobManagerService: JobManagerService, + private fb: FormBuilder, + private cdr: ChangeDetectorRef, + private nzModalService: NzModalService + ) { + super(messageService); + } + + ngOnInit() { + this.form = this.fb.group({ + noteName: [''], + interpreter: ['*'], + sortBy: [JobDateSortKeys.RECENTLY_UPDATED] + }); + + this.form.valueChanges.subscribe(() => this.filterJobs()); + + this.messageService.listNoteJobs(); + } + + ngOnDestroy(): void { + this.messageService.unsubscribeUpdateNoteJobs(); + super.ngOnDestroy(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts new file mode 100644 index 00000000000..5ce1f07028d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts @@ -0,0 +1,73 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; +import { IconDefinition } from '@ant-design/icons-angular'; +import { ClockCircleOutline, FileOutline, FileUnknownOutline, SearchOutline } from '@ant-design/icons-angular/icons'; +import { + NzBadgeModule, + NzCardModule, + NzDividerModule, + NzEmptyModule, + NzFormModule, + NzGridModule, + NzHighlightModule, + NzIconModule, + NzInputModule, + NzModalModule, + NzProgressModule, + NzSelectModule, + NzSkeletonModule, + NzToolTipModule, + NZ_ICONS +} from 'ng-zorro-antd'; + +import { ShareModule } from '@zeppelin/share'; + +import { JobManagerRoutingModule } from './job-manager-routing.module'; +import { JobManagerComponent } from './job-manager.component'; +import { JobManagerJobStatusComponent } from './job-status/job-status.component'; +import { JobManagerJobComponent } from './job/job.component'; + +const icons: IconDefinition[] = [SearchOutline, FileOutline, FileUnknownOutline, ClockCircleOutline]; + +@NgModule({ + declarations: [JobManagerComponent, JobManagerJobComponent, JobManagerJobStatusComponent], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + NzHighlightModule, + ShareModule, + NzIconModule, + NzInputModule, + NzBadgeModule, + NzGridModule, + NzModalModule, + RouterModule, + NzSelectModule, + NzInputModule, + NzFormModule, + JobManagerRoutingModule, + NzDividerModule, + NzCardModule, + NzToolTipModule, + NzProgressModule, + NzSkeletonModule, + NzEmptyModule + ], + providers: [{ provide: NZ_ICONS, useValue: icons }] +}) +export class JobManagerModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html new file mode 100644 index 00000000000..2bd375de558 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.html @@ -0,0 +1,17 @@ + + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less new file mode 100644 index 00000000000..0f2d8c0d122 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.less @@ -0,0 +1,23 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + display: inline-block; + nz-badge.ready { + ::ng-deep .ant-badge-status-success { + background: fade(@success-color, 20%); + border: 1px solid @success-color; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts new file mode 100644 index 00000000000..18828cd9827 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts @@ -0,0 +1,37 @@ +/* + * 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 { ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +import { JobStatus } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-job-manager-job-status', + templateUrl: './job-status.component.html', + styleUrls: ['./job-status.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JobManagerJobStatusComponent { + @Input() status: JobStatus; + @Input() showText = false; + jobStatus = JobStatus; + statusMap = { + [JobStatus.READY]: 'success', + [JobStatus.FINISHED]: 'success', + [JobStatus.ABORT]: 'warning', + [JobStatus.ERROR]: 'error', + [JobStatus.PENDING]: 'default', + [JobStatus.RUNNING]: 'processing' + }; + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html new file mode 100644 index 00000000000..4d76c7694aa --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html @@ -0,0 +1,58 @@ + + + +
+ + + - + + {{note.interpreter || 'interpreter is not set'}} + + + {{relativeTime}} + {{note.isRunningJob ? 'RUNNING' : 'READY'}} + {{progress | percent: '1.0-0'}} + + +
+ +
+ + diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less new file mode 100644 index 00000000000..bf958132e1c --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.less @@ -0,0 +1,70 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + display: block; + margin-bottom: 10px; + position: relative; + + ::ng-deep .job-item .ant-card-body { + padding: @card-padding-base / 2; + } + + .job-title { + margin-bottom: 10px; + } + + .note-icon { + margin-right: 5px; + } + + .right-tools { + display: inline-block; + float: right; + color: @text-color-secondary; + & > * { + margin-left: 5px; + } + .job-control-btn { + cursor: pointer; + color: @processing-color; + &.running { + color: @error-color; + } + } + } + + .interpreter { + color: @text-color; + &.unset { + color: @text-color-secondary; + } + } + + zeppelin-job-manager-job-status { + ::ng-deep .ant-badge-status-text { + margin-left: 0; + } + margin: 0 4px; + } + + .footer-progress { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + margin-bottom: -5px; + padding: 0 1px; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts new file mode 100644 index 00000000000..e2990c24922 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts @@ -0,0 +1,83 @@ +/* + * 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 { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges +} from '@angular/core'; + +import * as distanceInWords from 'date-fns/distance_in_words'; + +import { JobsItem, JobStatus } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-job-manager-job', + templateUrl: './job.component.html', + styleUrls: ['./job.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class JobManagerJobComponent implements OnInit, OnChanges { + @Input() note: JobsItem; + @Input() highlight: string | null = null; + @Output() readonly start = new EventEmitter(); + @Output() readonly stop = new EventEmitter(); + + icon = 'file'; + relativeTime = ''; + progress = 0; + + setIcon(): void { + const noteType = this.note.noteType; + if (noteType === 'normal') { + this.icon = 'file'; + } else if (noteType === 'cron') { + this.icon = 'close-circle'; + } else { + this.icon = 'file-unknown'; + } + } + + setRelativeTime(): void { + this.relativeTime = distanceInWords(new Date(), new Date(this.note.unixTimeLastRun)); + } + + setProgress(): void { + const runningCount = this.note.paragraphs.filter( + paragraph => [JobStatus.FINISHED, JobStatus.RUNNING].indexOf(paragraph.status) !== -1 + ).length; + this.progress = runningCount / this.note.paragraphs.length; + } + + onStartClick(): void { + this.start.emit(this.note.noteId); + } + + onStopClick(): void { + this.stop.emit(this.note.noteId); + } + + constructor() {} + + ngOnInit() {} + + ngOnChanges(changes: SimpleChanges): void { + this.setIcon(); + this.setRelativeTime(); + this.setProgress(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html new file mode 100644 index 00000000000..0238f171aca --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html @@ -0,0 +1,239 @@ + + +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
  • + {{r.message}} + + {{(r.time * 1000 | date: 'MMMM dd yyyy, h:mm:ss a') || 'Current'}} +
  • +
+
+
+ + + + + + + + + + + + + +
+ Run note with cron scheduler. + Either choose from preset or write your own + + cron expression + + . +
+ - Preset + {{cr.name}} +
+
+ - Preset + +

+ {{note.info.cron}} +

+
+
+ +
+
+
+
+
+
+ + + + + + +
    +
  • {{lf}}
  • +
+
+
+
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less new file mode 100644 index 00000000000..5161d77070a --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less @@ -0,0 +1,105 @@ +/* + * 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 "theme-mixin"; + +.scheduler { + width: 300px; + + .cron-preset { + margin-right: 6px; + + &.selected { + font-weight: bold; + } + } + + > div { + line-height: 24px; + + span { + margin-right: 6px; + } + + input { + display: inline-block; + width: 160px; + } + } +} + +.themeMixin({ + nz-dropdown-button { + height: 24px; + line-height: 22px; + margin-left: -1px; + } + .bar { + height: 50px; + background: @component-background; + box-shadow: -2px 4px 2px 0 rgba(0, 0, 0, 0.06); + padding: 0 15px; + position: absolute; + width: 100%; + top: 0; + line-height: 50px; + + &.simple { + box-shadow: none; + + .control { + display: none; + } + + .setting { + display: none; + } + + &:hover { + .control { + display: block; + } + + .setting { + display: block; + } + } + } + + .title { + float: left; + width: auto; + max-width: 40%; + } + + .control { + float: left; + + nz-button-group { + margin-right: 24px; + + &:last-child { + margin-right: 0; + } + } + } + + .setting { + float: right; + + button { + box-shadow: none; + border: none; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts new file mode 100644 index 00000000000..f4968d7988f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts @@ -0,0 +1,293 @@ +/* + * 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 { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Inject, + Input, + OnInit, + Output +} from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NzMessageService, NzModalService } from 'ng-zorro-antd'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { Note, OP, RevisionListItem } from '@zeppelin/sdk'; +import { MessageService, NoteActionService, NoteStatusService, SaveAsService, TicketService } from '@zeppelin/services'; + +import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; + +@Component({ + selector: 'zeppelin-notebook-action-bar', + templateUrl: './action-bar.component.html', + styleUrls: ['./action-bar.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookActionBarComponent extends MessageListenersManager implements OnInit { + @Input() note: Note['note']; + @Input() isOwner = true; + @Input() looknfeel: string; + @Input() noteRevisions: RevisionListItem[] = []; + @Input() currentRevision: string; + @Input() collaborativeMode = false; + @Input() collaborativeModeUsers = []; + @Input() revisionView = false; + @Input() activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + @Output() readonly activatedExtensionChange = new EventEmitter< + 'interpreter' | 'permissions' | 'revisions' | 'hide' + >(); + @Output() readonly editorHideChange = new EventEmitter(); + @Output() readonly tableHideChange = new EventEmitter(); + lfOption: Array<'report' | 'default' | 'simple'> = ['default', 'simple', 'report']; + isNoteParagraphRunning = false; + principal = this.ticketService.ticket.principal; + editorHide = false; + commitVisible = false; + tableHide = false; + isRevisionSupported = JSON.parse(this.ticketService.configuration.isRevisionSupported); + cronOption = [ + { name: 'None', value: undefined }, + { name: '1m', value: '0 0/1 * * * ?' }, + { name: '5m', value: '0 0/5 * * * ?' }, + { name: '1h', value: '0 0 0/1 * * ?' }, + { name: '3h', value: '0 0 0/3 * * ?' }, + { name: '6h', value: '0 0 0/6 * * ?' }, + { name: '12h', value: '0 0 0/12 * * ?' }, + { name: '1d', value: '0 0 0 * * ?' } + ]; + + updateNoteName(name: string) { + const trimmedNewName = name.trim(); + if (trimmedNewName.length > 0 && this.note.name !== trimmedNewName) { + this.note.name = trimmedNewName; + this.messageService.noteRename(this.note.id, this.note.name, true); + } + } + + visitRevision(revision: RevisionListItem) { + if (revision.id) { + if (revision.id === 'Head') { + this.router.navigate(['/notebook', this.activatedRoute.snapshot.params.noteId]).then(); + } else { + this.router.navigate(['/notebook', this.activatedRoute.snapshot.params.noteId, 'revision', revision.id]).then(); + } + } else { + this.nzMessageService.warning('There is a problem with this Revision'); + } + } + + checkpointNote(value: string, e: MouseEvent) { + e.preventDefault(); + this.commitVisible = false; + this.messageService.checkpointNote(this.note.id, value); + } + + setNoteRevision() { + const { revisionId } = this.activatedRoute.snapshot.params; + if (revisionId) { + this.nzModalService.confirm({ + nzTitle: 'Set revision', + nzContent: 'Set notebook head to current revision?', + nzOnOk: () => { + this.messageService.setNoteRevision(this.note.id, revisionId); + } + }); + } + } + + toggleExtension(extension: 'interpreter' | 'permissions' | 'revisions' | 'hide') { + if (this.activatedExtension === extension) { + this.activatedExtension = 'hide'; + } else { + this.activatedExtension = extension; + } + this.activatedExtensionChange.emit(this.activatedExtension); + } + + @MessageListener(OP.PARAGRAPH) + paragraphUpdate() { + this.updateIsNoteParagraphRunning(); + this.cdr.markForCheck(); + } + + runAllParagraphs() { + this.messageService.runAllParagraphs( + this.note.id, + this.note.paragraphs.map(p => { + return { + id: p.id, + title: p.title, + paragraph: p.text, + config: p.config, + params: p.settings.params + }; + }) + ); + } + + clearAllParagraphOutput() { + this.messageService.paragraphClearAllOutput(this.note.id); + } + + setCronScheduler(cronExpr: string) { + if (cronExpr) { + if (!this.note.config.cronExecutingUser) { + this.note.config.cronExecutingUser = this.ticketService.ticket.principal; + } + if (!this.note.config.cronExecutingRoles) { + this.note.config.cronExecutingRoles = this.ticketService.ticket.roles; + } + } else { + this.note.config.cronExecutingUser = ''; + this.note.config.cronExecutingRoles = ''; + } + this.note.config.cron = cronExpr; + this.setConfig(); + } + + setReleaseResource(releaseresource: boolean) { + this.note.config.releaseresource = releaseresource; + this.setConfig(); + } + + setConfig() { + // TODO(hsuanxyz) + } + + cloneNote() { + this.nzModalService.create({ + nzTitle: 'Clone Note', + nzContent: NoteCreateComponent, + nzComponentParams: { + cloneNote: this.note + }, + nzFooter: null + }); + } + + exportNote() { + const sizeLimit = +this.ticketService.configuration['zeppelin.websocket.max.text.message.size']; + const jsonContent = JSON.stringify(this.note); + if (jsonContent.length > sizeLimit) { + this.nzModalService.confirm({ + nzTitle: `Note size exceeds importable limit (${sizeLimit})`, + nzContent: 'Do you still want to export this note?', + nzOnOk: () => { + this.saveAsService.saveAs(jsonContent, this.note.name, 'zpln'); + } + }); + } else { + this.saveAsService.saveAs(jsonContent, this.note.name, 'zpln'); + } + } + + toggleAllEditor() { + this.editorHide = !this.editorHide; + this.editorHideChange.emit(this.editorHide); + } + + toggleAllTable() { + this.tableHide = !this.tableHide; + this.tableHideChange.emit(this.tableHide); + } + + searchCode() { + // TODO(hsuanxyz) + } + + deleteNote() { + this.messageService.deleteNote(this.note.id); + } + + moveNoteToTrash() { + this.messageService.moveNoteToTrash(this.note.id); + } + + get isTrash() { + return this.noteStatusService.isTrash(this.note); + } + + get viewOnly(): boolean { + return this.noteStatusService.viewOnly(this.note); + } + + updateIsNoteParagraphRunning() { + this.isNoteParagraphRunning = this.noteStatusService.isNoteParagraphRunning(this.note); + } + + showShortCut() { + // TODO(hsuanxyz) + } + + togglePermissions() { + this.toggleExtension('permissions'); + } + + setLookAndFeel(lf: 'report' | 'default' | 'simple') { + this.note.config.looknfeel = lf; + if (!this.activatedRoute.snapshot.params.revisionId) { + this.messageService.updateNote(this.note.id, this.note.name, this.note.config); + } + } + + toggleNotePersonalizedMode() { + const modeText = this.note.config.personalizedMode === 'true' ? 'collaborate' : 'personalize'; + if (this.isOwner) { + this.nzModalService.confirm({ + nzTitle: 'Setting the result display', + nzContent: `Do you want to ${modeText} your analysis?`, + nzOnOk: () => { + if (this.note.config.personalizedMode === undefined || this.note.config.personalizedMode === 'true') { + this.note.config.personalizedMode = 'false'; + } else { + this.note.config.personalizedMode = 'true'; + } + this.messageService.updatePersonalizedMode(this.note.id, this.note.config.personalizedMode); + } + }); + } + } + + get getCronOptionNameFromValue() { + if (!this.note.config.cron) { + return ''; + } else if (this.cronOption.find(cron => cron.value === this.note.config.cron)) { + return this.cronOption.find(cron => cron.value === this.note.config.cron).name; + } else { + return this.note.config.cron; + } + } + + constructor( + public messageService: MessageService, + private nzModalService: NzModalService, + private ticketService: TicketService, + private nzMessageService: NzMessageService, + private router: Router, + private cdr: ChangeDetectorRef, + private noteActionService: NoteActionService, + private noteStatusService: NoteStatusService, + @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, + private activatedRoute: ActivatedRoute, + private saveAsService: SaveAsService + ) { + super(messageService); + } + + ngOnInit(): void { + this.updateIsNoteParagraphRunning(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html new file mode 100644 index 00000000000..76d6475a7c5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.html @@ -0,0 +1,17 @@ + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less new file mode 100644 index 00000000000..c51b70e61a6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.less @@ -0,0 +1,50 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + .add-paragraph { + height: 32px; + text-align: center; + margin: -12px 0; + color: @primary-color; + font-weight: 500; + position: relative;; + + .inner { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 10; + display: none; + line-height: 30px; + background: @blue-1; + border: 1px solid @border-color-split; + box-shadow: @btn-shadow; + padding: 0 12px; + + &.disabled { + cursor: default; + color: @disabled-color; + } + } + + &:hover { + .inner { + display: block; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts new file mode 100644 index 00000000000..bb77a832979 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts @@ -0,0 +1,34 @@ +/* + * 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 { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; + +@Component({ + selector: 'zeppelin-notebook-add-paragraph', + templateUrl: './add-paragraph.component.html', + styleUrls: ['./add-paragraph.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookAddParagraphComponent implements OnInit { + @Output() readonly addParagraph = new EventEmitter(); + @Input() disabled = false; + + clickAdd() { + if (!this.disabled) { + this.addParagraph.emit(); + } + } + + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html new file mode 100644 index 00000000000..263390cbce6 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html @@ -0,0 +1,55 @@ + + +
+
+

Settings

+
+ +
+

Interpreter binding

+

+ Bind interpreter for this note. + Click to Bind/Unbind interpreter. + Drag and drop to reorder interpreters.
+ The first interpreter on the list becomes default. To create/remove interpreters, go to + Interpreter + menu. +

+
+
+
+
+ + + +
+ +
+
+
+
+ + +
+
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less new file mode 100644 index 00000000000..fcaea0a913f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.less @@ -0,0 +1,30 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + .interpreter-binding { + .interpreter-list { + background: @layout-body-background; + padding: 12px; + } + + .submit-interpreter { + margin-top: 12px; + + button { + margin-right: 12px; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts new file mode 100644 index 00000000000..377a869d1a4 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts @@ -0,0 +1,81 @@ +/* + * 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 { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core'; + +import { NzModalService } from 'ng-zorro-antd'; + +import { InterpreterBindingItem } from '@zeppelin/sdk'; +import { InterpreterService, MessageService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-interpreter-binding', + templateUrl: './interpreter-binding.component.html', + styleUrls: ['./interpreter-binding.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookInterpreterBindingComponent { + private restarting = false; + @Input() noteId: string; + @Input() interpreterBindings: InterpreterBindingItem[] = []; + @Input() activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + @Output() readonly activatedExtensionChange = new EventEmitter< + 'interpreter' | 'permissions' | 'revisions' | 'hide' + >(); + + restartInterpreter(interpreter: InterpreterBindingItem) { + this.nzModalService.create({ + nzTitle: 'Restart interpreter', + nzContent: `Do you want to restart ${interpreter.name} interpreter?`, + nzOkLoading: this.restarting, + nzOnOk: () => + new Promise(resolve => { + this.restarting = true; + this.interpreterService.restartInterpreter(interpreter.id, this.noteId).subscribe( + data => { + this.restarting = false; + this.cdr.markForCheck(); + resolve(); + }, + () => { + this.restarting = false; + resolve(); + } + ); + }) + }); + } + + drop(event: CdkDragDrop) { + moveItemInArray(this.interpreterBindings, event.previousIndex, event.currentIndex); + } + + saveSetting() { + const selectedSettingIds = this.interpreterBindings.filter(item => item.selected).map(item => item.id); + this.messageService.saveInterpreterBindings(this.noteId, selectedSettingIds); + this.messageService.getInterpreterBindings(this.noteId); + this.closeSetting(); + } + + closeSetting() { + this.activatedExtension = 'hide'; + this.activatedExtensionChange.emit('hide'); + } + + constructor( + private nzModalService: NzModalService, + private interpreterService: InterpreterService, + private cdr: ChangeDetectorRef, + private messageService: MessageService + ) {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts new file mode 100644 index 00000000000..6c177b6ba80 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts @@ -0,0 +1,37 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { NotebookComponent } from './notebook.component'; + +const routes: Routes = [ + { + path: ':noteId', + component: NotebookComponent + }, + { + path: ':noteId/paragraph/:paragraphId', + component: NotebookComponent + }, + { + path: ':noteId/revision/:revisionId', + component: NotebookComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class NotebookRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html new file mode 100644 index 00000000000..3bad5eec173 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -0,0 +1,54 @@ + + +
+ +
+ + + +
+
+
+ +
+
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less new file mode 100644 index 00000000000..582bbb74910 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.less @@ -0,0 +1,36 @@ +/* + * 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 "theme-mixin"; + + +.themeMixin({ + .notebook-container { + background: @layout-body-background; + display: block; + position: relative; + padding-top: 50px; + min-height: calc(~"100vh - 50px"); + + &.simple { + background: @component-background; + } + } + .extension-area { + padding: 24px; + background: @component-background; + box-shadow: -2px 4px 2px 0 rgba(0, 0, 0, 0.06); + } + .paragraph-area { + margin: 6px 0 0 0; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts new file mode 100644 index 00000000000..a894971b8e9 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -0,0 +1,315 @@ +/* + * 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 { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + OnDestroy, + OnInit, + QueryList, + ViewChildren +} from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { isNil } from 'lodash'; +import { Subject } from 'rxjs'; +import { distinctUntilKeyChanged, takeUntil } from 'rxjs/operators'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { Permissions } from '@zeppelin/interfaces'; +import { InterpreterBindingItem, MessageReceiveDataTypeMap, Note, OP, RevisionListItem } from '@zeppelin/sdk'; +import { + MessageService, + NoteStatusService, + NoteVarShareService, + SecurityService, + TicketService +} from '@zeppelin/services'; + +import { NotebookParagraphComponent } from './paragraph/paragraph.component'; + +@Component({ + selector: 'zeppelin-notebook', + templateUrl: './notebook.component.html', + styleUrls: ['./notebook.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookComponent extends MessageListenersManager implements OnInit, OnDestroy { + @ViewChildren(NotebookParagraphComponent) listOfNotebookParagraphComponent: QueryList; + private destroy$ = new Subject(); + note: Note['note']; + permissions: Permissions; + isOwner = true; + noteRevisions: RevisionListItem[] = []; + currentRevision: string; + collaborativeMode = false; + revisionView = false; + collaborativeModeUsers = []; + isNoteDirty = false; + saveTimer = null; + interpreterBindings: InterpreterBindingItem[] = []; + activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + + @MessageListener(OP.NOTE) + getNote(data: MessageReceiveDataTypeMap[OP.NOTE]) { + const note = data.note; + if (isNil(note)) { + this.router.navigate(['/']).then(); + } else { + this.note = note; + const { paragraphId } = this.activatedRoute.snapshot.params; + if (paragraphId) { + this.note = this.cleanParagraphExcept(paragraphId); + this.initializeLookAndFeel(); + } else { + this.initializeLookAndFeel(); + this.getInterpreterBindings(); + this.getPermissions(); + this.note.config.personalizedMode = + this.note.config.personalizedMode === undefined ? 'false' : this.note.config.personalizedMode; + } + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.INTERPRETER_BINDINGS) + loadInterpreterBindings(data: MessageReceiveDataTypeMap[OP.INTERPRETER_BINDINGS]) { + this.interpreterBindings = data.interpreterBindings; + if (!this.interpreterBindings.some(item => item.selected)) { + this.activatedExtension = 'interpreter'; + } + this.cdr.markForCheck(); + } + + @MessageListener(OP.PARAGRAPH_REMOVED) + removeParagraph(data: MessageReceiveDataTypeMap[OP.PARAGRAPH_REMOVED]) { + const { paragraphId } = this.activatedRoute.snapshot.params; + if (paragraphId || this.revisionView) { + return; + } + this.note.paragraphs = this.note.paragraphs.filter(p => p.id !== data.id); + this.cdr.markForCheck(); + } + + @MessageListener(OP.PARAGRAPH_ADDED) + addParagraph(data: MessageReceiveDataTypeMap[OP.PARAGRAPH_ADDED]) { + const { paragraphId } = this.activatedRoute.snapshot.params; + if (paragraphId || this.revisionView) { + return; + } + this.note.paragraphs.splice(data.index, 0, data.paragraph).map(p => { + return { + ...p, + focus: p.id === data.paragraph.id + }; + }); + this.note.paragraphs = [...this.note.paragraphs]; + this.cdr.markForCheck(); + // TODO(hsuanxyz) focus on paragraph + } + + @MessageListener(OP.SAVE_NOTE_FORMS) + saveNoteForms(data: MessageReceiveDataTypeMap[OP.SAVE_NOTE_FORMS]) { + this.note.noteForms = data.formsData.forms; + this.note.noteParams = data.formsData.params; + } + + @MessageListener(OP.NOTE_REVISION) + getNoteRevision(data: MessageReceiveDataTypeMap[OP.NOTE_REVISION]) { + const note = data.note; + if (isNil(note)) { + this.router.navigate(['/']).then(); + } else { + this.note = data.note; + this.initializeLookAndFeel(); + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.SET_NOTE_REVISION) + setNoteRevision() { + const { noteId } = this.activatedRoute.snapshot.params; + this.router.navigate(['/notebook', noteId]).then(); + } + + @MessageListener(OP.PARAGRAPH_MOVED) + moveParagraph(data: MessageReceiveDataTypeMap[OP.PARAGRAPH_MOVED]) { + if (!this.revisionView) { + const movedPara = this.note.paragraphs.find(p => p.id === data.id); + if (movedPara) { + const listOfRestPara = this.note.paragraphs.filter(p => p.id !== data.id); + this.note.paragraphs = [...listOfRestPara.slice(0, data.index), movedPara, ...listOfRestPara.slice(data.index)]; + this.cdr.markForCheck(); + } + } + } + + @MessageListener(OP.COLLABORATIVE_MODE_STATUS) + getCollaborativeModeStatus(data: MessageReceiveDataTypeMap[OP.COLLABORATIVE_MODE_STATUS]) { + this.collaborativeMode = Boolean(data.status); + this.collaborativeModeUsers = data.users; + this.cdr.markForCheck(); + } + + @MessageListener(OP.PATCH_PARAGRAPH) + patchParagraph() { + this.collaborativeMode = true; + this.cdr.markForCheck(); + } + + @MessageListener(OP.NOTE_UPDATED) + noteUpdated(data: MessageReceiveDataTypeMap[OP.NOTE_UPDATED]) { + if (data.name !== this.note.name) { + this.note.name = data.name; + } + this.note.config = data.config; + this.note.info = data.info; + this.initializeLookAndFeel(); + this.cdr.markForCheck(); + } + + @MessageListener(OP.LIST_REVISION_HISTORY) + listRevisionHistory(data: MessageReceiveDataTypeMap[OP.LIST_REVISION_HISTORY]) { + this.noteRevisions = data.revisionList; + if (this.noteRevisions) { + if (this.noteRevisions.length === 0 || this.noteRevisions[0].id !== 'Head') { + this.noteRevisions.splice(0, 0, { id: 'Head', message: 'Head' }); + } + const { revisionId } = this.activatedRoute.snapshot.params; + if (revisionId) { + this.currentRevision = this.noteRevisions.find(r => r.id === revisionId).message; + } else { + this.currentRevision = 'Head'; + } + } + this.cdr.markForCheck(); + } + + saveParagraph(id: string) { + this.listOfNotebookParagraphComponent + .toArray() + .find(p => p.paragraph.id === id) + .saveParagraph(); + } + + killSaveTimer() { + if (this.saveTimer) { + clearTimeout(this.saveTimer); + this.saveTimer = null; + } + } + + startSaveTimer() { + this.killSaveTimer(); + this.isNoteDirty = true; + this.saveTimer = setTimeout(() => { + this.saveNote(); + }, 10000); + } + + saveNote() { + if (this.note && this.note.paragraphs && this.listOfNotebookParagraphComponent) { + this.listOfNotebookParagraphComponent.toArray().forEach(p => { + p.saveParagraph(); + }); + this.isNoteDirty = null; + this.cdr.markForCheck(); + } + } + + getInterpreterBindings() { + this.messageService.getInterpreterBindings(this.note.id); + } + + getPermissions() { + this.securityService.getPermissions(this.note.id).subscribe(data => { + this.permissions = data; + this.isOwner = !( + this.permissions.owners.length && this.permissions.owners.indexOf(this.ticketService.ticket.principal) < 0 + ); + this.cdr.markForCheck(); + }); + } + + get viewOnly(): boolean { + return this.noteStatusService.viewOnly(this.note); + } + + initializeLookAndFeel() { + this.note.config.looknfeel = this.note.config.looknfeel || 'default'; + if (this.note.paragraphs && this.note.paragraphs[0]) { + this.note.paragraphs[0].focus = true; + } + } + + cleanParagraphExcept(paragraphId) { + const targetParagraph = this.note.paragraphs.find(p => p.id === paragraphId); + const config = targetParagraph.config || {}; + config.editorHide = true; + config.tableHide = false; + const paragraphs = [{ ...targetParagraph, config }]; + return { ...this.note, paragraphs }; + } + + setAllParagraphTableHide(tableHide: boolean) { + this.listOfNotebookParagraphComponent.forEach(p => p.setTableHide(tableHide)); + } + + setAllParagraphEditorHide(editorHide: boolean) { + this.listOfNotebookParagraphComponent.forEach(p => p.setEditorHide(editorHide)); + } + + constructor( + private activatedRoute: ActivatedRoute, + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private noteStatusService: NoteStatusService, + private noteVarShareService: NoteVarShareService, + private ticketService: TicketService, + private securityService: SecurityService, + private router: Router + ) { + super(messageService); + } + + ngOnInit() { + this.activatedRoute.params + .pipe( + takeUntil(this.destroy$), + distinctUntilKeyChanged('noteId') + ) + .subscribe(() => { + this.noteVarShareService.clear(); + }); + this.activatedRoute.params.pipe(takeUntil(this.destroy$)).subscribe(param => { + const { noteId, revisionId } = param; + if (revisionId) { + this.messageService.noteRevision(noteId, revisionId); + } else { + this.messageService.getNote(noteId); + } + this.revisionView = !!revisionId; + this.cdr.markForCheck(); + this.messageService.listRevisionHistory(noteId); + // TODO(hsuanxyz) scroll to current paragraph + }); + this.revisionView = !!this.activatedRoute.snapshot.params.revisionId; + } + + ngOnDestroy(): void { + super.ngOnDestroy(); + this.killSaveTimer(); + this.saveNote(); + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts new file mode 100644 index 00000000000..ccdd4de9dfd --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts @@ -0,0 +1,106 @@ +/* + * 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 { DragDropModule } from '@angular/cdk/drag-drop'; +import { PortalModule } from '@angular/cdk/portal'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { + NzButtonModule, + NzCheckboxModule, + NzDividerModule, + NzDropDownModule, + NzFormModule, + NzGridModule, + NzIconModule, + NzInputModule, + NzNoAnimationModule, + NzPopconfirmModule, + NzPopoverModule, + NzProgressModule, + NzRadioModule, + NzSelectModule, + NzSwitchModule, + NzToolTipModule +} from 'ng-zorro-antd'; +import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor'; +import { NzResizableModule } from 'ng-zorro-antd/resizable'; + +import { ShareModule } from '@zeppelin/share'; + +import { VisualizationModule } from 'src/app/visualizations/visualization.module'; +import { NotebookAddParagraphComponent } from './add-paragraph/add-paragraph.component'; +import { NotebookInterpreterBindingComponent } from './interpreter-binding/interpreter-binding.component'; +import { NotebookParagraphCodeEditorComponent } from './paragraph/code-editor/code-editor.component'; +import { NotebookParagraphControlComponent } from './paragraph/control/control.component'; +import { NotebookParagraphDynamicFormsComponent } from './paragraph/dynamic-forms/dynamic-forms.component'; +import { NotebookParagraphFooterComponent } from './paragraph/footer/footer.component'; +import { NotebookParagraphComponent } from './paragraph/paragraph.component'; +import { NotebookParagraphProgressComponent } from './paragraph/progress/progress.component'; +import { NotebookParagraphResultComponent } from './paragraph/result/result.component'; +import { NotebookPermissionsComponent } from './permissions/permissions.component'; +import { NotebookRevisionsComparatorComponent } from './revisions-comparator/revisions-comparator.component'; + +import { NotebookActionBarComponent } from './action-bar/action-bar.component'; +import { NotebookRoutingModule } from './notebook-routing.module'; +import { NotebookComponent } from './notebook.component'; +import { NotebookShareModule } from './share/share.module'; + +@NgModule({ + declarations: [ + NotebookComponent, + NotebookActionBarComponent, + NotebookInterpreterBindingComponent, + NotebookPermissionsComponent, + NotebookRevisionsComparatorComponent, + NotebookParagraphComponent, + NotebookAddParagraphComponent, + NotebookParagraphCodeEditorComponent, + NotebookParagraphResultComponent, + NotebookParagraphProgressComponent, + NotebookParagraphFooterComponent, + NotebookParagraphControlComponent, + NotebookParagraphDynamicFormsComponent + ], + imports: [ + CommonModule, + PortalModule, + NotebookRoutingModule, + ShareModule, + VisualizationModule, + NotebookShareModule, + NzButtonModule, + NzIconModule, + NzDropDownModule, + NzNoAnimationModule, + NzToolTipModule, + NzPopconfirmModule, + NzFormModule, + NzPopoverModule, + NzInputModule, + FormsModule, + ReactiveFormsModule, + NzDividerModule, + NzCheckboxModule, + NzProgressModule, + NzSwitchModule, + NzSelectModule, + NzGridModule, + NzRadioModule, + DragDropModule, + NzResizableModule, + NzCodeEditorModule + ] +}) +export class NotebookModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html new file mode 100644 index 00000000000..4d382f2b82f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html @@ -0,0 +1,16 @@ + + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less new file mode 100644 index 00000000000..72a1f689dc8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less @@ -0,0 +1,31 @@ +/* + * 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 "theme-mixin"; + +:host { + display: block; +} + +.themeMixin({ + + zeppelin-monaco-editor { + display: block; + border-left: 4px solid @border-color-split; + overflow: hidden; + + &.dirty { + border-left-color: @warning-color; + } + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts new file mode 100644 index 00000000000..6dabb4b2bbc --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -0,0 +1,238 @@ +/* + * 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 { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + NgZone, + OnChanges, + OnDestroy, + Output, + SimpleChanges +} from '@angular/core'; + +import { editor as MonacoEditor, IDisposable } from 'monaco-editor'; +import IStandaloneCodeEditor = MonacoEditor.IStandaloneCodeEditor; +import IEditor = monaco.editor.IEditor; + +import { InterpreterBindingItem } from '@zeppelin/sdk'; +import { CompletionService, MessageService } from '@zeppelin/services'; + +import { NotebookParagraphControlComponent } from '../control/control.component'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-code-editor', + templateUrl: './code-editor.component.html', + styleUrls: ['./code-editor.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestroy, AfterViewInit { + // TODO(hsuanxyz): + // 1. cursor position + @Input() readOnly = false; + @Input() language = 'text'; + @Input() paragraphControl: NotebookParagraphControlComponent; + @Input() lineNumbers = false; + @Input() focus = false; + @Input() collaborativeMode = false; + @Input() text: string; + @Input() fontSize: number; + @Input() dirty = false; + @Input() interpreterBindings: InterpreterBindingItem[] = []; + @Input() pid: string; + @Output() readonly textChanged = new EventEmitter(); + @Output() readonly editorBlur = new EventEmitter(); + private editor: IStandaloneCodeEditor; + private monacoDisposables: IDisposable[] = []; + height = 0; + interpreterName: string; + + autoAdjustEditorHeight() { + if (this.editor) { + this.ngZone.run(() => { + this.height = + this.editor.getTopForLineNumber(Number.MAX_SAFE_INTEGER) + this.editor.getConfiguration().lineHeight * 2; + this.editor.layout(); + this.cdr.markForCheck(); + }); + } + } + + initEditorListener() { + const editor = this.editor; + this.monacoDisposables.push( + editor.onDidFocusEditorText(() => { + this.ngZone.runOutsideAngular(() => { + editor.updateOptions({ renderLineHighlight: 'all' }); + }); + }), + editor.onDidBlurEditorText(() => { + this.editorBlur.emit(); + this.ngZone.runOutsideAngular(() => { + editor.updateOptions({ renderLineHighlight: 'none' }); + }); + }), + editor.onDidChangeModelContent(() => { + this.ngZone.run(() => { + this.text = editor.getModel().getValue(); + this.textChanged.emit(this.text); + this.setParagraphMode(true); + this.autoAdjustEditorHeight(); + setTimeout(() => { + this.autoAdjustEditorHeight(); + }); + }); + }) + ); + } + + setEditorValue() { + if (this.editor && this.editor.getModel() && this.editor.getModel().getValue() !== this.text) { + this.editor.getModel().setValue(this.text || ''); + } + } + + initializedEditor(editor: IEditor) { + this.editor = editor as IStandaloneCodeEditor; + this.paragraphControl.updateListOfMenu(monaco); + if (this.paragraphControl) { + this.paragraphControl.listOfMenu.forEach((item, index) => { + this.editor.addAction({ + id: item.icon, + label: item.label, + keybindings: item.keyBindings, + precondition: null, + keybindingContext: null, + contextMenuGroupId: 'navigation', + contextMenuOrder: index, + run: () => item.trigger() + }); + }); + } + + this.updateEditorOptions(); + this.setParagraphMode(); + this.initEditorListener(); + this.initEditorFocus(); + this.initCompletionService(); + this.setEditorValue(); + setTimeout(() => { + this.autoAdjustEditorHeight(); + }); + } + + initCompletionService(): void { + this.completionService.registerAsCompletionReceiver(this.editor.getModel(), this.paragraphControl.pid); + } + + initEditorFocus() { + if (this.focus && this.editor) { + this.editor.focus(); + } + } + + updateEditorOptions() { + if (this.editor) { + this.editor.updateOptions({ + readOnly: this.readOnly, + fontSize: this.fontSize, + renderLineHighlight: this.focus ? 'all' : 'none', + minimap: { enabled: false }, + lineNumbers: this.lineNumbers ? 'on' : 'off', + glyphMargin: false, + folding: false, + scrollBeyondLastLine: false + }); + } + } + + getInterpreterName(paragraphText: string) { + const match = /^\s*%(.+?)(\s|\()/g.exec(paragraphText); + if (match) { + return match[1].trim(); + // get default interpreter name if paragraph text doesn't start with '%' + // TODO(hsuanxyz): dig into the cause what makes interpreterBindings to have no element + } else if (this.interpreterBindings && this.interpreterBindings.length !== 0) { + return this.interpreterBindings[0].name; + } + return ''; + } + + setParagraphMode(changed = false) { + if (this.editor && !changed) { + const model = this.editor.getModel(); + if (this.language) { + // TODO(hsuanxyz): config convertMap + const convertMap = { + sh: 'shell' + }; + monaco.editor.setModelLanguage(model, convertMap[this.language] || this.language); + } + } else { + const interpreterName = this.getInterpreterName(this.text); + if (this.interpreterName !== interpreterName) { + this.interpreterName = interpreterName; + this.getEditorSetting(interpreterName); + } + } + } + + getEditorSetting(interpreterName: string) { + this.messageService.editorSetting(this.pid, interpreterName); + } + + layout() { + if (this.editor) { + setTimeout(() => { + this.editor.layout(); + }); + } + } + + constructor( + private cdr: ChangeDetectorRef, + private ngZone: NgZone, + private messageService: MessageService, + private completionService: CompletionService + ) {} + + ngOnChanges(changes: SimpleChanges): void { + const { text, interpreterBindings, language, readOnly, focus, lineNumbers, fontSize } = changes; + if (readOnly || focus || lineNumbers || fontSize) { + this.updateEditorOptions(); + } + if (focus) { + this.initEditorFocus(); + } + if (text) { + this.setEditorValue(); + } + + if (interpreterBindings || language) { + this.setParagraphMode(); + } + if (text || fontSize) { + this.autoAdjustEditorHeight(); + } + } + + ngOnDestroy(): void { + this.completionService.unregister(this.editor.getModel()); + this.monacoDisposables.forEach(d => d.dispose()); + } + + ngAfterViewInit(): void {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html new file mode 100644 index 00000000000..5ec5f52fccf --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.html @@ -0,0 +1,85 @@ + + + +
{{status}}
+
{{progress}}%
+ + + + + + + + + + + + + + + +
    +
  • + {{ pid }} +
  • +
  • +
  • + Run on selection change + +
  • +
  • + Width + + + +
  • +
  • + Font size + + + +
  • + +
  • + + {{menu.label}} + {{menu.shortCut}} +
  • +
    +
+
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less new file mode 100644 index 00000000000..700a6b666e8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.less @@ -0,0 +1,73 @@ +/* + * 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 "theme-mixin"; + +:host { + display: flex; +} + +.list-item { + display: flex; + justify-content: space-between; +} + +.setting-menu { + width: 270px; + + li { + font-size: 12px; + + i { + margin-right: 6px; + } + } +} + +.short-cut { + opacity: 0.7; +} + +.paragraph-id { + text-align: center; +} + +.themeMixin({ + .job-link { + margin-right: 12px; + + a { + color: @link-color; + } + } + .status { + color: @text-color-secondary; + margin-right: 12px; + } + .progress { + color: @text-color-secondary; + margin-right: 12px; + } + + a { + margin-left: 8px; + color: @text-color-secondary; + + .run-para { + color: @primary-color; + } + + .cancel-para { + color: @warning-color; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts new file mode 100644 index 00000000000..085fa266b2e --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -0,0 +1,304 @@ +/* + * 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 { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output +} from '@angular/core'; +import { copyTextToClipboard } from '@zeppelin/core'; + +import { NzMessageService, NzModalService } from 'ng-zorro-antd'; + +import { ActivatedRoute } from '@angular/router'; +import { RuntimeInfos } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-control', + exportAs: 'paragraphControl', + templateUrl: './control.component.html', + styleUrls: ['./control.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphControlComponent implements OnInit, OnChanges { + @Input() status: string; + @Input() progress = 0; + @Input() revisionView = false; + @Input() enabled = true; + @Input() pid: string; + @Input() tableHide = false; + @Input() editorHide = false; + @Input() colWidth: number; + @Input() fontSize: number; + @Input() runOnSelectionChange = true; + @Input() isEntireNoteRunning = true; + @Input() runtimeInfos: RuntimeInfos; + @Input() colWidthOption = []; + @Input() first = false; + @Input() last = false; + @Input() title = false; + @Input() lineNumbers = false; + @Input() paragraphLength: number; + @Output() readonly colWidthChange = new EventEmitter(); + @Output() readonly titleChange = new EventEmitter(); + @Output() readonly enabledChange = new EventEmitter(); + @Output() readonly fontSizeChange = new EventEmitter(); + @Output() readonly tableHideChange = new EventEmitter(); + @Output() readonly runParagraph = new EventEmitter(); + @Output() readonly lineNumbersChange = new EventEmitter(); + @Output() readonly cancelParagraph = new EventEmitter(); + @Output() readonly editorHideChange = new EventEmitter(); + @Output() readonly runOnSelectionChangeChange = new EventEmitter(); + @Output() readonly moveUp = new EventEmitter(); + @Output() readonly moveDown = new EventEmitter(); + @Output() readonly insertNew = new EventEmitter(); + @Output() readonly runAllAbove = new EventEmitter(); + @Output() readonly runAllBelowAndCurrent = new EventEmitter(); + @Output() readonly cloneParagraph = new EventEmitter(); + fontSizeOption = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; + dropdownVisible = false; + isMac = navigator.appVersion.indexOf('Mac') !== -1; + listOfMenu: Array<{ + label: string; + show: boolean; + disabled: boolean; + icon: string; + shortCut: string; + keyBindings: number[]; + trigger(): void; + }> = []; + + updateListOfMenu(monaco?) { + this.listOfMenu = [ + { + label: 'Move up', + show: !this.first, + disabled: this.isEntireNoteRunning, + icon: 'up', + trigger: () => this.trigger(this.moveUp), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+K`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_K] : [] + }, + { + label: 'Move down', + show: !this.last, + disabled: this.isEntireNoteRunning, + icon: 'down', + trigger: () => this.trigger(this.moveDown), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+J`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_J] : [] + }, + { + label: 'Insert new', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'plus', + trigger: () => this.trigger(this.insertNew), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+B`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_B] : [] + }, + { + label: 'Run all above', + show: !this.first, + disabled: this.isEntireNoteRunning, + icon: 'up-square', + trigger: () => this.trigger(this.runAllAbove), + shortCut: `Ctrl+Shift+Enter`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : [] + }, + { + label: 'Run all below', + show: !this.last, + disabled: this.isEntireNoteRunning, + icon: 'down-square', + trigger: () => this.trigger(this.runAllBelowAndCurrent), + shortCut: `Ctrl+Shift+Enter`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : [] + }, + { + label: 'Clone paragraph', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'copy', + trigger: () => this.trigger(this.cloneParagraph), + shortCut: `Ctrl+Shift+C`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.KEY_C] : [] + }, + { + label: this.title ? 'Hide Title' : 'Show Title', + show: true, + disabled: false, + icon: 'font-colors', + trigger: () => this.toggleTitle(), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+T`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_T] : [] + }, + { + label: this.lineNumbers ? 'Hide line numbers' : 'Show line numbers', + show: true, + disabled: false, + icon: 'ordered-list', + trigger: () => this.toggleLineNumbers(), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+M`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_M] : [] + }, + { + label: this.enabled ? 'Disable run' : 'Enable run', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'api', + trigger: () => this.toggleEnabled(), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+R`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_R] : [] + }, + { + label: 'Link this paragraph', + show: true, + disabled: false, + icon: 'export', + trigger: () => this.goToSingleParagraph(), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_W] : [] + }, + { + label: 'Clear output', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'fire', + trigger: () => this.clearParagraphOutput(), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+L`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_L] : [] + }, + { + label: 'Remove', + show: this.paragraphLength > 1, + disabled: this.isEntireNoteRunning, + icon: 'delete', + trigger: () => this.removeParagraph(), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+D`, + keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_D] : [] + } + ]; + } + + toggleEditor() { + this.editorHide = !this.editorHide; + this.editorHideChange.emit(this.editorHide); + } + + toggleOutput() { + this.tableHide = !this.tableHide; + this.tableHideChange.emit(this.tableHide); + } + + toggleRunOnSelectionChange() { + this.runOnSelectionChange = !this.runOnSelectionChange; + this.runOnSelectionChangeChange.emit(this.runOnSelectionChange); + } + + toggleTitle() { + this.title = !this.title; + this.titleChange.emit(this.title); + } + + toggleLineNumbers() { + this.lineNumbers = !this.lineNumbers; + this.lineNumbersChange.emit(this.lineNumbers); + } + + toggleEnabled() { + if (!this.isEntireNoteRunning) { + this.enabled = !this.enabled; + this.enabledChange.emit(this.enabled); + } + } + + goToSingleParagraph() { + // TODO(hsuanxyz) asIframe + const { noteId } = this.activatedRoute.snapshot.params; + const redirectToUrl = `${location.protocol}//${location.host}${location.pathname}#/notebook/${noteId}/paragraph/${this.pid}`; + window.open(redirectToUrl); + } + + changeColWidth(colWidth: number) { + this.colWidth = +colWidth; + this.colWidthChange.emit(this.colWidth); + this.dropdownVisible = false; + } + + changeFontSize(fontSize: number) { + this.fontSize = +fontSize; + this.fontSizeChange.emit(this.fontSize); + } + + copyClipboard(id: string) { + copyTextToClipboard(id); + this.nzMessageService.info('Paragraph id copied'); + } + + clearParagraphOutput() { + if (!this.isEntireNoteRunning) { + this.messageService.paragraphClearOutput(this.pid); + } + } + + removeParagraph() { + if (!this.isEntireNoteRunning) { + if (this.paragraphLength === 1) { + this.nzModalService.warning({ + nzTitle: `Warning`, + nzContent: `All the paragraphs can't be deleted` + }); + } else { + this.nzModalService.confirm({ + nzTitle: 'Delete Paragraph', + nzContent: 'Do you want to delete this paragraph?', + nzOnOk: () => { + this.messageService.paragraphRemove(this.pid); + this.cdr.markForCheck(); + // TODO(hsuanxyz) moveFocusToNextParagraph + } + }); + } + } + } + + trigger(event: EventEmitter) { + if (!this.isEntireNoteRunning) { + this.dropdownVisible = false; + event.emit(); + } + } + + constructor( + private cdr: ChangeDetectorRef, + private nzMessageService: NzMessageService, + private activatedRoute: ActivatedRoute, + private messageService: MessageService, + private nzModalService: NzModalService + ) {} + + ngOnInit() { + this.updateListOfMenu(); + } + + ngOnChanges(): void { + this.updateListOfMenu(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html new file mode 100644 index 00000000000..3a4cfdd5ff0 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html @@ -0,0 +1,51 @@ + + +
+
+ + + + + + + + + + +
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less new file mode 100644 index 00000000000..060b2f8485d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less @@ -0,0 +1,24 @@ +/* + * 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. + */ + +:host { + display: block; + .form-item { + margin-bottom: 24px; + nz-select { + width: 100%; + } + ::ng-deep .ant-checkbox-wrapper { + margin-left: 0; + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts new file mode 100644 index 00000000000..0dab7ec7221 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts @@ -0,0 +1,120 @@ +/* + * 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 { + ChangeDetectionStrategy, + Component, + EventEmitter, + HostListener, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + SimpleChanges +} from '@angular/core'; +import { Subject } from 'rxjs'; +import { debounceTime, takeUntil } from 'rxjs/operators'; + +import { NzCheckBoxOptionInterface } from 'ng-zorro-antd'; + +import { DynamicForms, DynamicFormsItem, DynamicFormsType, DynamicFormParams } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-dynamic-forms', + templateUrl: './dynamic-forms.component.html', + styleUrls: ['./dynamic-forms.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphDynamicFormsComponent implements OnInit, OnChanges, OnDestroy { + private destroy$ = new Subject(); + + @Input() formDefs: DynamicForms; + @Input() paramDefs: DynamicFormParams; + @Input() runOnChange = false; + @Input() disable = false; + @Output() readonly formChange = new EventEmitter(); + + formChange$ = new Subject(); + forms: DynamicFormsItem[] = []; + formType = DynamicFormsType; + checkboxGroups: { + [key: string]: NzCheckBoxOptionInterface[]; + } = {}; + + @HostListener('keydown.enter') + onEnter() { + if (!this.runOnChange) { + this.formChange.emit(); + } + } + + trackByNameFn(_index, form: DynamicFormsItem) { + return form.name; + } + + setForms() { + this.forms = Object.values(this.formDefs); + this.checkboxGroups = {}; + this.forms.forEach(e => { + if (!this.paramDefs[e.name]) { + this.paramDefs[e.name] = e.defaultValue; + } + if (e.type === DynamicFormsType.CheckBox) { + this.checkboxGroups[e.name] = e.options.map(opt => { + let checked = false; + if (this.paramDefs[e.name] && Array.isArray(this.paramDefs[e.name])) { + const param = this.paramDefs[e.name] as string[]; + checked = param.indexOf(opt.value) !== -1; + } + return { + checked, + label: opt.displayName || opt.value, + value: opt.value + }; + }); + } + }); + } + + checkboxChange(value: NzCheckBoxOptionInterface[], name) { + this.paramDefs[name] = value.filter(e => e.checked).map(e => e.value); + this.onFormChange(); + } + + onFormChange() { + if (this.runOnChange) { + this.formChange$.next(); + } + } + + constructor() {} + + ngOnInit() { + this.setForms(); + this.formChange$ + .pipe( + debounceTime(800), + takeUntil(this.destroy$) + ) + .subscribe(() => this.formChange.emit()); + } + + ngOnChanges(changes: SimpleChanges): void { + this.setForms(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html new file mode 100644 index 00000000000..677356b1d5d --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html @@ -0,0 +1,16 @@ + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less new file mode 100644 index 00000000000..767a5491765 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.less @@ -0,0 +1,21 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + .footer { + color: @text-color-secondary; + font-size: 12px; + margin-top: 12px; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts new file mode 100644 index 00000000000..1be51ca9c31 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts @@ -0,0 +1,74 @@ +/* + * 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 { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; + +import * as distanceInWordsStrict from 'date-fns/distance_in_words_strict'; +import * as distanceInWordsToNow from 'date-fns/distance_in_words_to_now'; +import * as format from 'date-fns/format'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphFooterComponent implements OnChanges { + @Input() dateStarted: string; + @Input() dateFinished: string; + @Input() dateUpdated: string; + @Input() showExecutionTime = false; + @Input() showElapsedTime = false; + @Input() user: string; + executionTime: string; + elapsedTime: string; + + isResultOutdated() { + return this.dateUpdated !== undefined && Date.parse(this.dateUpdated) > Date.parse(this.dateStarted); + } + + getExecutionTime() { + const end = this.dateFinished; + const start = this.dateStarted; + const timeMs = Date.parse(end) - Date.parse(start); + if (isNaN(timeMs) || timeMs < 0) { + if (this.isResultOutdated()) { + return 'outdated'; + } + return ''; + } + + const durationFormat = distanceInWordsStrict(start, end); + const endFormat = format(this.dateFinished, 'MMMM DD YYYY, h:mm:ss A'); + + const user = this.user === undefined || this.user === null ? 'anonymous' : this.user; + let desc = `Took ${durationFormat}. Last updated by ${user} at ${endFormat}.`; + + if (this.isResultOutdated()) { + desc += ' (outdated)'; + } + + return desc; + } + + getElapsedTime() { + // TODO(hsuanxyz) dateStarted undefined after start + return `Started ${distanceInWordsToNow(this.dateStarted || new Date())} ago.`; + } + + constructor() {} + + ngOnChanges() { + this.executionTime = this.getExecutionTime(); + this.elapsedTime = this.getElapsedTime(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html new file mode 100644 index 00000000000..861f955e261 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -0,0 +1,99 @@ + + +
+ +
+ + + + + + + + + + + +
+ +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less new file mode 100644 index 00000000000..f24d693f1e8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less @@ -0,0 +1,72 @@ +/* + * 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 "theme-mixin"; + +:host { + display: block; + padding: 0 4px; +} + +.themeMixin({ + .paragraph { + background: @component-background; + border: 1px solid @border-color-split; + box-shadow: @card-shadow; + padding: 32px 12px 12px 12px; + position: relative; + + zeppelin-notebook-paragraph-code-editor + zeppelin-notebook-paragraph-dynamic-forms { + margin-top: 24px; + } + + zeppelin-notebook-paragraph-progress + zeppelin-notebook-paragraph-dynamic-forms { + margin-top: 24px; + } + + &.simple { + box-shadow: none; + border-color: transparent; + + zeppelin-notebook-paragraph-control, zeppelin-notebook-paragraph-footer { + visibility: hidden; + } + + &:hover { + border: 1px solid @border-color-split; + box-shadow: @card-shadow; + + zeppelin-notebook-paragraph-control, zeppelin-notebook-paragraph-footer { + visibility: visible; + } + } + } + + &.report { + &:hover { + box-shadow: none; + border-color: transparent; + + zeppelin-notebook-paragraph-control, zeppelin-notebook-paragraph-footer { + visibility: hidden; + } + } + } + + zeppelin-notebook-paragraph-control { + position: absolute; + right: 12px; + top: 8px; + z-index: 10; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts new file mode 100644 index 00000000000..21d57bb6e17 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -0,0 +1,653 @@ +/* + * 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 { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + OnDestroy, + OnInit, + Output, + QueryList, + ViewChild, + ViewChildren +} from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import DiffMatchPatch from 'diff-match-patch'; +import { isEmpty, isEqual } from 'lodash'; +import { NzModalService } from 'ng-zorro-antd'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { + AngularObjectRemove, + AngularObjectUpdate, + GraphConfig, + InterpreterBindingItem, + MessageReceiveDataTypeMap, + Note, + OP, + ParagraphConfig, + ParagraphConfigResult, + ParagraphEditorSetting, + ParagraphItem, + ParagraphIResultsMsgItem +} from '@zeppelin/sdk'; +import { + HeliumService, + MessageService, + NgZService, + NoteStatusService, + NoteVarShareService, + ParagraphStatus +} from '@zeppelin/services'; +import { SpellResult } from '@zeppelin/spell/spell-result'; + +import { NzResizeEvent } from 'ng-zorro-antd/resizable'; +import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component'; +import { NotebookParagraphResultComponent } from './result/result.component'; + +@Component({ + selector: 'zeppelin-notebook-paragraph', + templateUrl: './paragraph.component.html', + styleUrls: ['./paragraph.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphComponent extends MessageListenersManager implements OnInit, OnChanges, OnDestroy { + @ViewChild(NotebookParagraphCodeEditorComponent, { static: false }) + notebookParagraphCodeEditorComponent: NotebookParagraphCodeEditorComponent; + @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList< + NotebookParagraphResultComponent + >; + @Input() paragraph: ParagraphItem; + @Input() note: Note['note']; + @Input() looknfeel: string; + @Input() revisionView: boolean; + @Input() viewOnly: boolean; + @Input() last: boolean; + @Input() collaborativeMode = false; + @Input() first: boolean; + @Input() interpreterBindings: InterpreterBindingItem[] = []; + @Output() readonly saveNoteTimer = new EventEmitter(); + @Output() readonly triggerSaveParagraph = new EventEmitter(); + + private destroy$ = new Subject(); + dirtyText: string; + originalText: string; + isEntireNoteRunning = false; + diffMatchPatch = new DiffMatchPatch(); + isParagraphRunning = false; + results = []; + configs = {}; + progress = 0; + colWidthOption = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + editorSetting: ParagraphEditorSetting = {}; + + @MessageListener(OP.PROGRESS) + onProgress(data: MessageReceiveDataTypeMap[OP.PROGRESS]) { + if (data.id === this.paragraph.id) { + this.progress = data.progress; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.NOTE_RUNNING_STATUS) + noteRunningStatusChange(data: MessageReceiveDataTypeMap[OP.NOTE_RUNNING_STATUS]) { + this.isEntireNoteRunning = data.status; + this.cdr.markForCheck(); + } + + @MessageListener(OP.PARAS_INFO) + updateParaInfos(data: MessageReceiveDataTypeMap[OP.PARAS_INFO]) { + if (this.paragraph.id === data.id) { + this.paragraph.runtimeInfos = data.infos; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.EDITOR_SETTING) + getEditorSetting(data: MessageReceiveDataTypeMap[OP.EDITOR_SETTING]) { + if (this.paragraph.id === data.paragraphId) { + this.paragraph.config.editorSetting = { ...this.paragraph.config.editorSetting, ...data.editor }; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.PARAGRAPH) + paragraphData(data: MessageReceiveDataTypeMap[OP.PARAGRAPH]) { + const oldPara = this.paragraph; + const newPara = data.paragraph; + if (this.isUpdateRequired(oldPara, newPara)) { + this.updateParagraph(oldPara, newPara, () => { + if (newPara.results && newPara.results.msg) { + // tslint:disable-next-line:no-for-in-array + for (const i in newPara.results.msg) { + if (newPara.results.msg[i]) { + const newResult = newPara.results.msg ? newPara.results.msg[i] : new ParagraphIResultsMsgItem(); + const oldResult = + oldPara.results && oldPara.results.msg ? oldPara.results.msg[i] : new ParagraphIResultsMsgItem(); + const newConfig = newPara.config.results ? newPara.config.results[i] : { graph: new GraphConfig() }; + const oldConfig = oldPara.config.results ? oldPara.config.results[i] : { graph: new GraphConfig() }; + if (!isEqual(newResult, oldResult) || !isEqual(newConfig, oldConfig)) { + const resultComponent = this.notebookParagraphResultComponents.toArray()[i]; + if (resultComponent) { + resultComponent.updateResult(newConfig, newResult); + } + } + } + } + } + this.cdr.markForCheck(); + }); + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.PATCH_PARAGRAPH) + patchParagraph(data: MessageReceiveDataTypeMap[OP.PATCH_PARAGRAPH]) { + if (data.paragraphId === this.paragraph.id) { + let patch = data.patch; + patch = this.diffMatchPatch.patch_fromText(patch); + if (!this.paragraph.text) { + this.paragraph.text = ''; + } + this.paragraph.text = this.diffMatchPatch.patch_apply(patch, this.paragraph.text)[0]; + this.originalText = this.paragraph.text; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.ANGULAR_OBJECT_UPDATE) + angularObjectUpdate(data: AngularObjectUpdate) { + if (data.paragraphId === this.paragraph.id) { + const { name, object } = data.angularObject; + this.ngZService.setContextValue(name, object, data.paragraphId, false); + } + } + + @MessageListener(OP.ANGULAR_OBJECT_REMOVE) + angularObjectRemove(data: AngularObjectRemove) { + if (data.paragraphId === this.paragraph.id) { + this.ngZService.unsetContextValue(data.name, data.paragraphId, false); + } + } + + updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) { + // 1. can't update on revision view + if (!this.revisionView) { + // 2. get status, refreshed + const statusChanged = newPara.status !== oldPara.status; + const resultRefreshed = + newPara.dateFinished !== oldPara.dateFinished || + isEmpty(newPara.results) !== isEmpty(oldPara.results) || + newPara.status === ParagraphStatus.ERROR || + (newPara.status === ParagraphStatus.FINISHED && statusChanged); + + // 3. update texts managed by paragraph + this.updateAllScopeTexts(oldPara, newPara); + // 4. execute callback to update result + updateCallback(); + + // 5. update remaining paragraph objects + this.updateParagraphObjectWhenUpdated(newPara); + + // 6. handle scroll down by key properly if new paragraph is added + if (statusChanged || resultRefreshed) { + // when last paragraph runs, zeppelin automatically appends new paragraph. + // this broadcast will focus to the newly inserted paragraph + // TODO(hsuanxyz) + } + this.cdr.markForCheck(); + } + } + + textChanged(text: string) { + this.dirtyText = text; + this.paragraph.text = text; + if (this.dirtyText !== this.originalText) { + if (this.collaborativeMode) { + this.sendPatch(); + } else { + this.startSaveTimer(); + } + } + } + + sendPatch() { + this.originalText = this.originalText ? this.originalText : ''; + const patch = this.diffMatchPatch.patch_make(this.originalText, this.dirtyText).toString(); + this.originalText = this.dirtyText; + this.messageService.patchParagraph(this.paragraph.id, this.note.id, patch); + } + + startSaveTimer() { + this.saveNoteTimer.emit(); + } + + saveParagraph() { + const dirtyText = this.paragraph.text; + if (dirtyText === undefined || dirtyText === this.originalText) { + return; + } + this.commitParagraph(); + this.originalText = dirtyText; + this.dirtyText = undefined; + this.cdr.markForCheck(); + } + + runAllAbove() { + const index = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id); + const toRunParagraphs = this.note.paragraphs.filter((p, i) => i < index); + + const paragraphs = toRunParagraphs.map(p => { + return { + id: p.id, + title: p.title, + paragraph: p.text, + config: p.config, + params: p.settings.params + }; + }); + this.nzModalService.confirm({ + nzTitle: 'Run all above?', + nzContent: 'Are you sure to run all above paragraphs?', + nzOnOk: () => { + this.messageService.runAllParagraphs(this.note.id, paragraphs); + } + }); + // TODO(hsuanxyz): save cursor + } + + doubleClickParagraph() { + if (this.paragraph.config.editorSetting.editOnDblClick && this.revisionView !== true) { + this.paragraph.config.editorHide = false; + this.paragraph.config.tableHide = true; + // TODO(hsuanxyz): focus editor + } + } + + runAllBelowAndCurrent() { + const index = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id); + const toRunParagraphs = this.note.paragraphs.filter((p, i) => i >= index); + + const paragraphs = toRunParagraphs.map(p => { + return { + id: p.id, + title: p.title, + paragraph: p.text, + config: p.config, + params: p.settings.params + }; + }); + this.nzModalService.confirm({ + nzTitle: 'Run current and all below?', + nzContent: 'Are you sure to run current and all below?', + nzOnOk: () => { + this.messageService.runAllParagraphs(this.note.id, paragraphs); + } + }); + // TODO(hsuanxyz): save cursor + } + + cloneParagraph(position: string = 'below') { + let newIndex = -1; + for (let i = 0; i < this.note.paragraphs.length; i++) { + if (this.note.paragraphs[i].id === this.paragraph.id) { + // determine position of where to add new paragraph; default is below + if (position === 'above') { + newIndex = i; + } else { + newIndex = i + 1; + } + break; + } + } + + if (newIndex < 0 || newIndex > this.note.paragraphs.length) { + return; + } + + const config = this.paragraph.config; + config.editorHide = false; + + this.messageService.copyParagraph( + newIndex, + this.paragraph.title, + this.paragraph.text, + config, + this.paragraph.settings.params + ); + } + + runParagraph(paragraphText?: string, propagated: boolean = false) { + const text = paragraphText || this.paragraph.text; + if (text && !this.isParagraphRunning) { + const magic = SpellResult.extractMagic(text); + + if (this.heliumService.getSpellByMagic(magic)) { + this.runParagraphUsingSpell(text, magic, propagated); + } else { + this.runParagraphUsingBackendInterpreter(text); + } + + this.originalText = text; + this.dirtyText = undefined; + + if (this.paragraph.config.editorSetting.editOnDblClick) { + this.paragraph.config.editorHide = true; + this.paragraph.config.tableHide = false; + this.commitParagraph(); + } else if (this.editorSetting.isOutputHidden && !this.paragraph.config.editorSetting.editOnDblClick) { + // %md/%angular repl make output to be hidden by default after running + // so should open output if repl changed from %md/%angular to another + this.paragraph.config.editorHide = false; + this.paragraph.config.tableHide = false; + this.commitParagraph(); + } + this.editorSetting.isOutputHidden = this.paragraph.config.editorSetting.editOnDblClick; + } + } + + runParagraphUsingSpell(paragraphText: string, magic: string, propagated: boolean) { + // TODO(hsuanxyz) + } + + runParagraphUsingBackendInterpreter(paragraphText: string) { + this.messageService.runParagraph( + this.paragraph.id, + this.paragraph.title, + paragraphText, + this.paragraph.config, + this.paragraph.settings.params + ); + } + + cancelParagraph() { + if (!this.isEntireNoteRunning) { + this.messageService.cancelParagraph(this.paragraph.id); + } + } + + updateAllScopeTexts(oldPara: ParagraphItem, newPara: ParagraphItem) { + if (oldPara.text !== newPara.text) { + if (this.dirtyText) { + // check if editor has local update + if (this.dirtyText === newPara.text) { + // when local update is the same from remote, clear local update + this.paragraph.text = newPara.text; + this.dirtyText = undefined; + this.originalText = newPara.text; + } else { + // if there're local update, keep it. + this.paragraph.text = newPara.text; + } + } else { + this.paragraph.text = newPara.text; + this.originalText = newPara.text; + } + } + this.cdr.markForCheck(); + } + + updateParagraphObjectWhenUpdated(newPara: ParagraphItem) { + if (this.paragraph.config.colWidth !== newPara.config.colWidth) { + this.changeColWidth(false); + } + this.paragraph.aborted = newPara.aborted; + this.paragraph.user = newPara.user; + this.paragraph.dateUpdated = newPara.dateUpdated; + this.paragraph.dateCreated = newPara.dateCreated; + this.paragraph.dateFinished = newPara.dateFinished; + this.paragraph.dateStarted = newPara.dateStarted; + this.paragraph.errorMessage = newPara.errorMessage; + this.paragraph.jobName = newPara.jobName; + this.paragraph.title = newPara.title; + this.paragraph.lineNumbers = newPara.lineNumbers; + this.paragraph.status = newPara.status; + this.paragraph.fontSize = newPara.fontSize; + if (newPara.status !== ParagraphStatus.RUNNING) { + this.paragraph.results = newPara.results; + } + this.paragraph.settings = newPara.settings; + this.paragraph.runtimeInfos = newPara.runtimeInfos; + this.isParagraphRunning = this.noteStatusService.isParagraphRunning(newPara); + this.paragraph.config = newPara.config; + this.initializeDefault(this.paragraph.config); + this.setResults(); + this.cdr.markForCheck(); + } + + isUpdateRequired(oldPara: ParagraphItem, newPara: ParagraphItem): boolean { + return ( + newPara.id === oldPara.id && + (newPara.dateCreated !== oldPara.dateCreated || + newPara.text !== oldPara.text || + newPara.dateFinished !== oldPara.dateFinished || + newPara.dateStarted !== oldPara.dateStarted || + newPara.dateUpdated !== oldPara.dateUpdated || + newPara.status !== oldPara.status || + newPara.jobName !== oldPara.jobName || + newPara.title !== oldPara.title || + isEmpty(newPara.results) !== isEmpty(oldPara.results) || + newPara.errorMessage !== oldPara.errorMessage || + !isEqual(newPara.settings, oldPara.settings) || + !isEqual(newPara.config, oldPara.config) || + !isEqual(newPara.runtimeInfos, oldPara.runtimeInfos)) + ); + } + + insertParagraph(position: string) { + if (this.revisionView === true) { + return; + } + let newIndex = -1; + for (let i = 0; i < this.note.paragraphs.length; i++) { + if (this.note.paragraphs[i].id === this.paragraph.id) { + // determine position of where to add new paragraph; default is below + if (position === 'above') { + newIndex = i; + } else { + newIndex = i + 1; + } + break; + } + } + + if (newIndex < 0 || newIndex > this.note.paragraphs.length) { + return; + } + this.messageService.insertParagraph(newIndex); + this.cdr.markForCheck(); + } + + setResults() { + if (this.paragraph.results) { + this.results = this.paragraph.results.msg; + this.configs = this.paragraph.config.results; + } + if (!this.paragraph.config) { + this.paragraph.config = {}; + } + } + + setTitle(title: string) { + this.paragraph.title = title; + this.commitParagraph(); + this.cdr.markForCheck(); + } + + commitParagraph() { + const { + id, + title, + text, + config, + settings: { params } + } = this.paragraph; + this.messageService.commitParagraph(id, title, text, config, params, this.note.id); + } + + initializeDefault(config: ParagraphConfig) { + const forms = this.paragraph.settings.forms; + + if (!config.colWidth) { + config.colWidth = 12; + } + + if (!config.fontSize) { + config.fontSize = 9; + } + + if (config.enabled === undefined) { + config.enabled = true; + } + + for (const idx in forms) { + if (forms[idx]) { + if (forms[idx].options) { + if (config.runOnSelectionChange === undefined) { + config.runOnSelectionChange = true; + } + } + } + } + + if (!config.results) { + config.results = {}; + } + + if (!config.editorSetting) { + config.editorSetting = {}; + } else if (config.editorSetting.editOnDblClick) { + this.editorSetting.isOutputHidden = config.editorSetting.editOnDblClick; + } + } + + moveUpParagraph() { + const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) - 1; + if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { + return; + } + // save dirtyText of moving paragraphs. + const prevParagraph = this.note.paragraphs[newIndex]; + // TODO(hsuanxyz): save pre paragraph? + this.saveParagraph(); + this.triggerSaveParagraph.emit(prevParagraph.id); + this.messageService.moveParagraph(this.paragraph.id, newIndex); + } + + moveDownParagraph() { + const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) + 1; + if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { + return; + } + // save dirtyText of moving paragraphs. + const nextParagraph = this.note.paragraphs[newIndex]; + // TODO(hsuanxyz): save pre paragraph? + this.saveParagraph(); + this.triggerSaveParagraph.emit(nextParagraph.id); + this.messageService.moveParagraph(this.paragraph.id, newIndex); + } + + changeColWidth(needCommit: boolean, updateResult = true) { + if (needCommit) { + this.commitParagraph(); + } + if (this.notebookParagraphCodeEditorComponent) { + this.notebookParagraphCodeEditorComponent.layout(); + } + + if (updateResult) { + this.notebookParagraphResultComponents.forEach(comp => { + comp.setGraphConfig(); + }); + } + } + + onSizeChange(resize: NzResizeEvent) { + this.paragraph.config.colWidth = resize.col; + this.changeColWidth(true, false); + this.cdr.markForCheck(); + } + + onConfigChange(configResult: ParagraphConfigResult, index: number) { + this.paragraph.config.results[index] = configResult; + this.commitParagraph(); + this.cdr.markForCheck(); + } + + setEditorHide(editorHide: boolean) { + this.paragraph.config.editorHide = editorHide; + this.cdr.markForCheck(); + } + + setTableHide(tableHide: boolean) { + this.paragraph.config.tableHide = tableHide; + this.cdr.markForCheck(); + } + + trackByIndexFn(index: number) { + return index; + } + + constructor( + private heliumService: HeliumService, + private noteStatusService: NoteStatusService, + public messageService: MessageService, + private nzModalService: NzModalService, + private noteVarShareService: NoteVarShareService, + private cdr: ChangeDetectorRef, + private ngZService: NgZService + ) { + super(messageService); + } + + ngOnInit() { + this.setResults(); + this.originalText = this.paragraph.text; + this.isEntireNoteRunning = this.noteStatusService.isEntireNoteRunning(this.note); + this.isParagraphRunning = this.noteStatusService.isParagraphRunning(this.paragraph); + this.noteVarShareService.set(this.paragraph.id + '_paragraphScope', this); + this.initializeDefault(this.paragraph.config); + this.ngZService + .runParagraphAction() + .pipe(takeUntil(this.destroy$)) + .subscribe(id => { + if (id === this.paragraph.id) { + this.runParagraph(); + } + }); + this.ngZService + .contextChanged() + .pipe(takeUntil(this.destroy$)) + .subscribe(change => { + if (change.paragraphId === this.paragraph.id && change.emit) { + if (change.set) { + this.messageService.angularObjectClientBind(this.note.id, change.key, change.value, change.paragraphId); + } else { + this.messageService.angularObjectClientUnbind(this.note.id, change.key, change.paragraphId); + } + } + }); + } + + ngOnChanges(): void {} + + ngOnDestroy(): void { + super.ngOnDestroy(); + this.ngZService.removeParagraph(this.paragraph.id); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html new file mode 100644 index 00000000000..07c886a22d0 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.html @@ -0,0 +1,16 @@ + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts new file mode 100644 index 00000000000..ce205a0ad59 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts @@ -0,0 +1,32 @@ +/* + * 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 { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-progress', + templateUrl: './progress.component.html', + styleUrls: ['./progress.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphProgressComponent implements OnChanges { + @Input() progress = 0; + displayProgress = 0; + + ngOnChanges(): void { + if (this.progress > 0 && this.progress < 100) { + this.displayProgress = this.progress; + } else { + this.displayProgress = 100; + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html new file mode 100644 index 00000000000..028c3e50089 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html @@ -0,0 +1,74 @@ + + +
+
+ + + +
+ + + + + + +
    +
  • CSV
  • +
  • TSV
  • +
+
+ + + Setting + + +
+
+ + + + + +
+
+
img
+
+
+ +
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less new file mode 100644 index 00000000000..f1970729ab9 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less @@ -0,0 +1,78 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + display: block; + + .nz-resizable-preview { + left: -12px; + padding-right: 10px; + border: none; + &::before { + content: ' '; + display: block; + border: 1px dashed #d1d1d1; + width: 100%; + height: 100%; + } + } + + ::ng-deep { + .inner-html, .text-plain { + + overflow: auto; + + ol, ul, dl { + padding-left: 20px; + } + + img { + max-width: 100%; + height: auto; + width: auto; + } + } + } + + .text-plain { + font-size: 12px; + color: @text-color; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + } + .setting-bar { + display: flex; + margin: 10px 0; + + .export-dropdown { + margin: 0 20px; + + .export-dropdown-icon-btn { + width: 32px; + height: 32px; + padding: 0; + font-size: 16px; + } + } + + .setting-trigger { + line-height: 32px; + + i { + font-size: 12px; + } + } + + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts new file mode 100644 index 00000000000..850bc18a394 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts @@ -0,0 +1,360 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + EventEmitter, + Injector, + Input, + OnDestroy, + OnInit, + Output, + ViewChild, + ViewContainerRef +} from '@angular/core'; +import { DomSanitizer, SafeHtml, SafeUrl } from '@angular/platform-browser'; +import { Subject, Subscription } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import * as Convert from 'ansi-to-html'; +import * as hljs from 'highlight.js'; +import { NzResizeEvent } from 'ng-zorro-antd/resizable'; +import { utils, writeFile, WorkSheet, WritingOptions } from 'xlsx'; + +import { + DatasetType, + GraphConfig, + ParagraphConfigResult, + ParagraphIResultsMsgItem, + VisualizationLineChart, + VisualizationMode, + VisualizationMultiBarChart, + VisualizationScatterChart, + VisualizationStackedAreaChart +} from '@zeppelin/sdk'; + +import { ZeppelinHeliumService } from '@zeppelin/helium'; +import { TableData, Visualization } from '@zeppelin/visualization'; + +import { HeliumManagerService } from '@zeppelin/helium-manager'; +import { DynamicTemplate, NgZService, RuntimeCompilerService } from '@zeppelin/services'; +import { AreaChartVisualization } from '@zeppelin/visualizations/area-chart/area-chart-visualization'; +import { BarChartVisualization } from '@zeppelin/visualizations/bar-chart/bar-chart-visualization'; +import { LineChartVisualization } from '@zeppelin/visualizations/line-chart/line-chart-visualization'; +import { PieChartVisualization } from '@zeppelin/visualizations/pie-chart/pie-chart-visualization'; +import { ScatterChartVisualization } from '@zeppelin/visualizations/scatter-chart/scatter-chart-visualization'; +import { TableVisualization } from '@zeppelin/visualizations/table/table-visualization'; + +@Component({ + selector: 'zeppelin-notebook-paragraph-result', + templateUrl: './result.component.html', + styleUrls: ['./result.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, OnDestroy { + @Input() result: ParagraphIResultsMsgItem; + @Input() config: ParagraphConfigResult; + @Input() id: string; + @Input() currentCol = 12; + @Output() readonly configChange = new EventEmitter(); + @Output() readonly sizeChange = new EventEmitter(); + @ViewChild(CdkPortalOutlet, { static: false }) portalOutlet: CdkPortalOutlet; + + private destroy$ = new Subject(); + datasetType = DatasetType; + angularComponent: DynamicTemplate; + innerHTML: string | SafeHtml = ''; + plainText: string | SafeHtml = ''; + imgData: string | SafeUrl = ''; + tableData = new TableData(); + // tslint:disable-next-line:no-any + visualizations: any[] = [ + { + id: 'table', + name: 'Table', + icon: 'table', + Class: TableVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'multiBarChart', + name: 'Bar Chart', + icon: 'bar-chart', + Class: BarChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'pieChart', + name: 'Pie Chart', + icon: 'pie-chart', + Class: PieChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'lineChart', + name: 'Line Chart', + icon: 'line-chart', + Class: LineChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'stackedAreaChart', + name: 'Area Chart', + icon: 'area-chart', + Class: AreaChartVisualization, + changeSubscription: null, + instance: undefined + }, + { + id: 'scatterChart', + name: 'Scatter Chart', + icon: 'dot-chart', + Class: ScatterChartVisualization, + changeSubscription: null, + instance: undefined + } + ]; + + constructor( + private viewContainerRef: ViewContainerRef, + private cdr: ChangeDetectorRef, + private runtimeCompilerService: RuntimeCompilerService, + private sanitizer: DomSanitizer, + private injector: Injector, + private ngZService: NgZService, + private zeppelinHeliumService: ZeppelinHeliumService, + private heliumManagerService: HeliumManagerService + ) { + this.heliumManagerService + .packagesLoadChange() + .pipe(takeUntil(this.destroy$)) + .subscribe(packages => { + packages.forEach(pack => { + this.visualizations.push({ + id: pack._raw.id, + name: pack.name, + icon: pack._raw.icon, + Class: pack._raw.visualization, + componentFactoryResolver: pack.moduleFactory.create(this.injector).componentFactoryResolver, + changeSubscription: null, + instance: undefined + }); + }); + this.cdr.markForCheck(); + }); + } + + ngOnInit() { + this.ngZService + .contextChanged() + .pipe(takeUntil(this.destroy$)) + .subscribe(change => { + if (change.paragraphId === this.id) { + this.cdr.markForCheck(); + } + }); + } + + exportFile(type: 'csv' | 'tsv'): void { + if (this.tableData && this.tableData.rows) { + const wb = utils.book_new(); + let ws: WorkSheet; + ws = utils.json_to_sheet(this.tableData.rows); + utils.book_append_sheet(wb, ws, 'Sheet1'); + writeFile(wb, `export.${type}`, { + bookType: 'csv', + FS: type === 'tsv' ? '\t' : ',' + } as WritingOptions); + } + } + + switchMode(mode: VisualizationMode) { + this.config.graph.mode = mode; + this.renderGraph(); + this.configChange.emit(this.config); + } + + switchSetting() { + this.config.graph.optionOpen = !this.config.graph.optionOpen; + this.renderGraph(); + this.configChange.emit(this.config); + } + + updateResult(config: ParagraphConfigResult, result: ParagraphIResultsMsgItem) { + this.config = config; + this.result = result; + this.renderDefaultDisplay(); + } + + renderDefaultDisplay() { + switch (this.result.type) { + case DatasetType.TABLE: + this.renderGraph(); + break; + case DatasetType.TEXT: + this.renderText(); + break; + case DatasetType.HTML: + this.renderHTML(); + break; + case DatasetType.IMG: + this.renderImg(); + break; + case DatasetType.ANGULAR: + this.renderAngular(); + break; + } + this.cdr.markForCheck(); + } + + renderHTML(): void { + const div = document.createElement('div'); + div.innerHTML = this.result.data; + const codeEle: HTMLElement = div.querySelector('pre code'); + if (codeEle) { + hljs.highlightBlock(codeEle); + } + this.innerHTML = this.sanitizer.bypassSecurityTrustHtml(div.innerHTML); + } + + renderAngular(): void { + this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => { + this.angularComponent = data; + // this.angularComponent.moduleFactory + this.cdr.markForCheck(); + }); + } + + renderText(): void { + // tslint:disable-next-line:no-any + const convert: any = new Convert(); + this.plainText = this.sanitizer.bypassSecurityTrustHtml(convert.toHtml(this.result.data)); + } + + renderImg(): void { + this.imgData = this.sanitizer.bypassSecurityTrustUrl(`data:image/png;base64,${this.result.data}`); + } + + setGraphConfig() { + const visualizationItem = this.visualizations.find(v => v.id === this.config.graph.mode); + if (!visualizationItem || !visualizationItem.instance) { + return; + } + visualizationItem.instance.setConfig(this.config.graph); + } + + renderGraph() { + this.setDefaultConfig(); + let instance: Visualization; + const visualizationItem = this.visualizations.find(v => v.id === this.config.graph.mode); + if (!visualizationItem) { + return; + } + this.destroyVisualizations(this.config.graph.mode); + if (!visualizationItem.instance) { + // tslint:disable-next-line:no-any + instance = new visualizationItem.Class( + this.config.graph, + this.portalOutlet, + this.viewContainerRef, + visualizationItem.componentFactoryResolver + ); + visualizationItem.instance = instance; + visualizationItem.changeSubscription = instance.configChanged().subscribe(config => { + this.config.graph = config; + this.renderGraph(); + this.configChange.emit({ + graph: config + }); + }); + } else { + instance = visualizationItem.instance; + instance.setConfig(this.config.graph); + } + this.tableData.loadParagraphResult(this.result); + const transformation = instance.getTransformation(); + transformation.setConfig(this.config.graph); + transformation.setTableData(this.tableData); + const transformed = transformation.transform(this.tableData); + instance.render(transformed); + } + + destroyVisualizations(omit?: string) { + this.visualizations.forEach(v => { + if (v.id !== omit && v.instance) { + if (v.changeSubscription instanceof Subscription) { + v.changeSubscription.unsubscribe(); + v.changeSubscription = null; + } + if (typeof v.instance.destroy === 'function') { + v.instance.destroy(); + } + v.instance = undefined; + } + }); + } + + setDefaultConfig() { + if (!this.config || !this.config.graph) { + this.config = { graph: new GraphConfig() }; + } + if (!this.config.graph.setting) { + this.config.graph.setting = {}; + } + if (!this.config.graph.setting[this.config.graph.mode]) { + switch (this.config.graph.mode) { + case 'multiBarChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationMultiBarChart(); + break; + case 'stackedAreaChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationStackedAreaChart(); + break; + case 'lineChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationLineChart(); + break; + case 'scatterChart': + this.config.graph.setting[this.config.graph.mode] = new VisualizationScatterChart(); + break; + default: + break; + } + } + } + + onResize($event: NzResizeEvent) { + const { width, height, col } = $event; + if (this.result.type === DatasetType.TABLE) { + this.config.graph.height = height; + this.setGraphConfig(); + } + this.sizeChange.emit({ width, height, col }); + } + + ngAfterViewInit(): void { + this.renderDefaultDisplay(); + } + + ngOnDestroy(): void { + this.destroyVisualizations(); + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html new file mode 100644 index 00000000000..c3e699d4aef --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html @@ -0,0 +1,88 @@ + + +
+
+

Note Permissions (Only note owners can change)

+
+ +
+

+ Enter comma separated users and groups in the fields.
+ Empty field (*) implies anyone can do the operation. +

+
+
+
+ + Owners + + + + + + + + + + Owners can change permissions,read, run and write the note. + + + + Writers + + + + + + + + + + Writers can read, run and write the note. + + + + Runners + + + + + + + + + + Runners can read and run the note. + + + + Readers + + + + + + + + + + Readers can only read the note. + + +
+
+ + +
+
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less new file mode 100644 index 00000000000..146cd37f4af --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.less @@ -0,0 +1,33 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + .permissions-form { + background: @layout-body-background; + padding: 12px; + margin-bottom: 12px; + } + nz-form-item { + margin-bottom: 12px; + + &:last-child { + margin-bottom: 0; + } + } + .submit-permissions { + button { + margin-right: 12px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts new file mode 100644 index 00000000000..eb749c108fb --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts @@ -0,0 +1,135 @@ +/* + * 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 { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output +} from '@angular/core'; + +import { NzMessageService, NzModalService } from 'ng-zorro-antd'; + +import { Permissions } from '@zeppelin/interfaces'; +import { SecurityService, TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-permissions', + templateUrl: './permissions.component.html', + styleUrls: ['./permissions.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookPermissionsComponent implements OnInit, OnChanges { + @Input() permissions: Permissions; + @Input() noteId: string; + @Input() activatedExtension: 'interpreter' | 'permissions' | 'revisions' | 'hide' = 'hide'; + @Output() readonly activatedExtensionChange = new EventEmitter< + 'interpreter' | 'permissions' | 'revisions' | 'hide' + >(); + permissionsBack: Permissions; + listOfUserAndRole = []; + + savePermissions() { + const principal = this.ticketService.ticket.principal; + const isAnonymous = principal === 'anonymous'; + if (isAnonymous || this.ticketService.ticket.principal.trim().length === 0) { + this.blockAnonUsers(); + } + if (this.isOwnerEmpty()) { + this.nzModalService.create({ + nzTitle: 'Setting Owners Permissions', + nzContent: `Please fill the [Owners] field. If not, it will set as current user. Current user : [ ${this.ticketService.ticket.principal.trim()} ]`, + nzOnOk: () => { + this.permissions.owners = [this.ticketService.ticket.principal]; + this.setPermissions(); + }, + nzOnCancel: () => { + this.resetPermissions(); + } + }); + } else { + this.setPermissions(); + } + } + + closePermissions() { + this.activatedExtension = 'hide'; + this.activatedExtensionChange.emit('hide'); + } + + blockAnonUsers() { + this.nzModalService.create({ + nzTitle: 'No permission', + nzContent: 'Only authenticated user can set the permission.', + nzOkText: 'Read Doc', + nzOnOk: () => { + const url = `https://zeppelin.apache.org/docs/${this.ticketService.version}/security/notebook_authorization.html`; + window.open(url); + } + }); + } + + setPermissions() { + this.securityService.setPermissions(this.noteId, this.permissions).subscribe(() => { + this.nzMessageService.success('Permissions Saved Successfully'); + this.closePermissions(); + }); + } + + resetPermissions() { + this.permissions = { ...this.permissionsBack }; + } + + isOwnerEmpty() { + return !this.permissions.owners.some(o => o.trim().length > 0); + } + + searchUser(search: string) { + this.securityService.searchUsers(search).subscribe(data => { + const results = []; + if (data.users.length) { + results.push({ + text: 'Users :', + children: data.users + }); + } + if (data.roles.length) { + results.push({ + text: 'Roles :', + children: data.roles + }); + } + this.listOfUserAndRole = results; + this.cdr.markForCheck(); + }); + } + + constructor( + private securityService: SecurityService, + private cdr: ChangeDetectorRef, + private nzMessageService: NzMessageService, + private ticketService: TicketService, + private nzModalService: NzModalService + ) {} + + ngOnInit() { + this.permissionsBack = { ...this.permissions }; + } + + ngOnChanges(): void { + this.permissionsBack = { ...this.permissions }; + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html new file mode 100644 index 00000000000..6f0e1be83f1 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html @@ -0,0 +1,20 @@ + + +
+
+

Revisions comparator

+
+ +
+
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts new file mode 100644 index 00000000000..1876b3cbbdb --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts @@ -0,0 +1,25 @@ +/* + * 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 { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'zeppelin-notebook-revisions-comparator', + templateUrl: './revisions-comparator.component.html', + styleUrls: ['./revisions-comparator.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookRevisionsComparatorComponent implements OnInit { + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html new file mode 100644 index 00000000000..c605d28771b --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html @@ -0,0 +1,23 @@ + + +
+ +

{{value || 'Untitled'}}

+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less new file mode 100644 index 00000000000..6efdd89a7aa --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.less @@ -0,0 +1,56 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + .elastic { + margin-right: 24px; + overflow: hidden; + max-width: 100%; + + &.min { + margin-bottom: 6px; + margin-right: 0; + p, input { + font-size: 16px; + padding: 0 1px; + } + + input { + height: 24px; + margin: 0; + padding: 0; + } + } + + p, input { + font-size: 28px; + width: 100%; + font-weight: 700; + } + + p { + margin: 0 1px; + padding: 0 11px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + input { + height: 36px; + margin: 7px 0; + padding: 0 10px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts new file mode 100644 index 00000000000..ef4dce4e988 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts @@ -0,0 +1,88 @@ +/* + * 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 { + ChangeDetectionStrategy, + Component, + ElementRef, + EventEmitter, + Input, + OnChanges, + Output, + Renderer2, + SimpleChanges, + ViewChild +} from '@angular/core'; + +@Component({ + selector: 'zeppelin-elastic-input', + templateUrl: './elastic-input.component.html', + styleUrls: ['./elastic-input.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ElasticInputComponent implements OnChanges { + @Input() value: string; + @Input() readonly = false; + @Input() min = false; + @Output() readonly valueUpdate = new EventEmitter(); + @ViewChild('inputElement', { read: ElementRef, static: false }) inputElement: ElementRef; + @ViewChild('pElement', { read: ElementRef, static: false }) pElement: ElementRef; + @ViewChild('elasticElement', { read: ElementRef, static: true }) elasticElement: ElementRef; + showEditor = false; + editValue: string; + + cancelEdit() { + this.editValue = this.value; + this.showEditor = false; + } + + updateValue(value: string) { + const trimmedNewName = value.trim(); + if (trimmedNewName.length > 0 && this.value !== trimmedNewName) { + this.editValue = trimmedNewName; + } + } + + setEditorState(showEditor: boolean) { + if (!this.readonly) { + this.showEditor = showEditor; + if (!this.showEditor) { + this.valueUpdate.emit(this.editValue); + } else { + const width = this.pElement.nativeElement.getBoundingClientRect().width; + this.renderer.setStyle(this.elasticElement.nativeElement, 'width', `${width}px`); + setTimeout(() => { + this.inputElement.nativeElement.focus(); + this.renderer.setStyle(this.inputElement.nativeElement, 'width', `${width}px`); + }); + } + } + } + + updateInputWidth() { + const width = this.inputElement.nativeElement.scrollWidth; + if (width > this.inputElement.nativeElement.getBoundingClientRect().width) { + this.renderer.removeStyle(this.elasticElement.nativeElement, 'width'); + this.renderer.setStyle(this.inputElement.nativeElement, 'width', `${width}px`); + } + } + + constructor(private renderer: Renderer2) {} + + ngOnChanges(changes: SimpleChanges) { + if (changes.value) { + this.showEditor = false; + this.editValue = this.value; + this.renderer.removeStyle(this.elasticElement.nativeElement, 'width'); + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts new file mode 100644 index 00000000000..c97c48ec89a --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts @@ -0,0 +1,26 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NzInputModule } from 'ng-zorro-antd'; + +import { ElasticInputComponent } from './elastic-input/elastic-input.component'; + +@NgModule({ + declarations: [ElasticInputComponent], + exports: [ElasticInputComponent], + imports: [CommonModule, NzInputModule, FormsModule] +}) +export class NotebookShareModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts new file mode 100644 index 00000000000..0340a8d1499 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts @@ -0,0 +1,51 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { WorkspaceComponent } from './workspace.component'; +import { WorkspaceGuard } from './workspace.guard'; + +const routes: Routes = [ + { + path: '', + component: WorkspaceComponent, + canActivate: [WorkspaceGuard], + children: [ + { + path: '', + loadChildren: () => import('@zeppelin/pages/workspace/home/home.module').then(m => m.HomeModule) + }, + { + path: 'notebook', + loadChildren: () => import('@zeppelin/pages/workspace/notebook/notebook.module').then(m => m.NotebookModule) + }, + { + path: 'jobmanager', + loadChildren: () => + import('@zeppelin/pages/workspace/job-manager/job-manager.module').then(m => m.JobManagerModule) + }, + { + path: 'interpreter', + loadChildren: () => + import('@zeppelin/pages/workspace/interpreter/interpreter.module').then(m => m.InterpreterModule) + } + ] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class WorkspaceRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html new file mode 100644 index 00000000000..6bcae47ad44 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html @@ -0,0 +1,17 @@ + + +
+ + +
+Connecting WebSocket ... diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less new file mode 100644 index 00000000000..63064aabd16 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less @@ -0,0 +1,26 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .content { + background: @layout-body-background; + min-height: 100vh; + display: block; + position: relative; + + &.blur { + filter: blur(4px); + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts new file mode 100644 index 00000000000..03c5b9b0f75 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts @@ -0,0 +1,48 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { HeliumManagerService } from '@zeppelin/helium-manager'; +import { MessageService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-workspace', + templateUrl: './workspace.component.html', + styleUrls: ['./workspace.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class WorkspaceComponent implements OnInit, OnDestroy { + private destroy$ = new Subject(); + websocketConnected = false; + + constructor( + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private heliumManagerService: HeliumManagerService + ) {} + + ngOnInit() { + this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(data => { + this.websocketConnected = data; + this.cdr.markForCheck(); + }); + this.heliumManagerService.initPackages(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts new file mode 100644 index 00000000000..b491d750cc4 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.guard.ts @@ -0,0 +1,36 @@ +/* + * 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 { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router'; +import { of, Observable } from 'rxjs'; +import { catchError, mapTo, tap } from 'rxjs/operators'; + +import { MessageService, TicketService } from '@zeppelin/services'; + +@Injectable({ + providedIn: 'root' +}) +export class WorkspaceGuard implements CanActivate { + constructor(private ticketService: TicketService, private router: Router, private messageService: MessageService) {} + + canActivate( + next: ActivatedRouteSnapshot, + state: RouterStateSnapshot + ): Observable | Promise | boolean | UrlTree { + return this.ticketService.getTicket().pipe( + mapTo(true), + tap(() => this.messageService.bootstrap()), + catchError(() => of(this.router.createUrlTree(['/login']))) + ); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts new file mode 100644 index 00000000000..f6e01e28861 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts @@ -0,0 +1,37 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; + +import { HeliumManagerModule } from '@zeppelin/helium-manager'; +import { ShareModule } from '@zeppelin/share'; + +import { WorkspaceRoutingModule } from './workspace-routing.module'; +import { WorkspaceComponent } from './workspace.component'; + +@NgModule({ + declarations: [WorkspaceComponent], + imports: [ + CommonModule, + WorkspaceRoutingModule, + FormsModule, + HttpClientModule, + ShareModule, + RouterModule, + HeliumManagerModule + ] +}) +export class WorkspaceModule {} diff --git a/zeppelin-web-angular/src/app/services/array-ordering.service.ts b/zeppelin-web-angular/src/app/services/array-ordering.service.ts new file mode 100644 index 00000000000..766f729fd90 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/array-ordering.service.ts @@ -0,0 +1,62 @@ +/* + * 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 { Inject, Injectable } from '@angular/core'; +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; + +@Injectable({ + providedIn: 'root' +}) +export class ArrayOrderingService { + noteListOrdering(note) { + if (note.id === this.TRASH_FOLDER_ID) { + return '\uFFFF'; + } + return this.getNoteName(note); + } + + getNoteName(note) { + if (note.name === undefined || note.name.trim() === '') { + return 'Note ' + note.id; + } else { + return note.name; + } + } + + noteComparator = (v1, v2) => { + const note1 = v1.value || v1; + const note2 = v2.value || v2; + + if (note1.id === this.TRASH_FOLDER_ID) { + return 1; + } + + if (note2.id === this.TRASH_FOLDER_ID) { + return -1; + } + + if (note1.children === undefined && note2.children !== undefined) { + return 1; + } + + if (note1.children !== undefined && note2.children === undefined) { + return -1; + } + + const noteName1 = this.getNoteName(note1); + const noteName2 = this.getNoteName(note2); + + return noteName1.localeCompare(noteName2); + }; + + constructor(@Inject(TRASH_FOLDER_ID_TOKEN) private TRASH_FOLDER_ID: string) {} +} diff --git a/zeppelin-web-angular/src/app/services/base-rest.ts b/zeppelin-web-angular/src/app/services/base-rest.ts new file mode 100644 index 00000000000..7f0ba1b0a19 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/base-rest.ts @@ -0,0 +1,45 @@ +/* + * 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 { BaseUrlService } from './base-url.service'; + +/** + * @private + */ +export class BaseRest { + constructor(public baseUrlService: BaseUrlService) {} + + /** + * ```ts + * this.restUrl`/user/${username}` + * this.restUrl(['/user/'], username) + * this.restUrl(`/user/${username}`) + * ``` + * @param str` + * @param values + */ + restUrl(str: TemplateStringsArray | string, ...values): string { + let output = this.baseUrlService.getRestApiBase(); + + if (typeof str === 'string') { + return `${output}${str}`; + } + + let index; + for (index = 0; index < values.length; index++) { + output += str[index] + values[index]; + } + + output += str[index]; + return output; + } +} diff --git a/zeppelin-web-angular/src/app/services/base-url.service.ts b/zeppelin-web-angular/src/app/services/base-url.service.ts new file mode 100644 index 00000000000..c6c6a3d83f7 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/base-url.service.ts @@ -0,0 +1,46 @@ +/* + * 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 { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class BaseUrlService { + getPort() { + let port = Number(location.port); + if (!port) { + port = 80; + if (location.protocol === 'https:') { + port = 443; + } + } + return port; + } + + getWebsocketUrl() { + const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:'; + return `${wsProtocol}//${location.hostname}:${this.getPort()}${this.skipTrailingSlash(location.pathname)}/ws`; + } + + getBase() { + return `${location.protocol}//${location.hostname}:${this.getPort()}${location.pathname}`; + } + + getRestApiBase() { + return this.skipTrailingSlash(this.getBase()) + '/api'; + } + + skipTrailingSlash(path) { + return path.replace(/\/$/, ''); + } +} diff --git a/zeppelin-web-angular/src/app/services/completion.service.ts b/zeppelin-web-angular/src/app/services/completion.service.ts new file mode 100644 index 00000000000..9f772ecb95e --- /dev/null +++ b/zeppelin-web-angular/src/app/services/completion.service.ts @@ -0,0 +1,97 @@ +/* + * 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 { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; +import { filter, map, take } from 'rxjs/operators'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { CompletionReceived, OP } from '@zeppelin/sdk'; + +import { MessageService } from './message.service'; + +@Injectable({ + providedIn: 'root' +}) +export class CompletionService extends MessageListenersManager { + private completionLanguages = ['python', 'scala']; + private completionItem$ = new Subject(); + private receivers = new WeakMap(); + private bound = false; + + constructor(messageService: MessageService) { + super(messageService); + } + + @MessageListener(OP.COMPLETION_LIST) + onCompletion(data?: CompletionReceived): void { + console.log('on receive!', data.id); + this.completionItem$.next(data); + } + + registerAsCompletionReceiver(model: monaco.editor.ITextModel, pid: string): void { + if (this.receivers.has(model)) { + return; + } + + if (!this.bound) { + this.bindMonacoCompletion(); + this.bound = true; + } + + this.receivers.set(model, pid); + } + + unregister(model: monaco.editor.ITextModel): void { + this.receivers.delete(model); + } + + private bindMonacoCompletion(): void { + // tslint:disable-next-line:no-this-assignment + const that = this; + + this.completionLanguages.forEach(l => { + monaco.languages.registerCompletionItemProvider(l, { + provideCompletionItems(model: monaco.editor.ITextModel, position: monaco.Position) { + const id = that.getIdForModel(model); + + if (!id) { + return { suggestions: null }; + } + + that.messageService.completion(id, model.getValue(), model.getOffsetAt(position)); + + return that.completionItem$ + .pipe( + filter(d => d.id === id), + take(1), + map(d => { + return { + suggestions: d.completions.map(i => ({ + kind: monaco.languages.CompletionItemKind.Keyword, + label: i.name, + insertText: i.name, + range: undefined + })) + }; + }) + ) + .toPromise(); + } + }); + }); + } + + private getIdForModel(model?: monaco.editor.ITextModel): string | null { + return this.receivers.get(model); + } +} diff --git a/zeppelin-web-angular/src/app/services/helium.service.ts b/zeppelin-web-angular/src/app/services/helium.service.ts new file mode 100644 index 00000000000..327c6987f88 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/helium.service.ts @@ -0,0 +1,24 @@ +/* + * 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 { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class HeliumService { + getSpellByMagic(magic: string): string { + return null; + } + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/services/index.ts b/zeppelin-web-angular/src/app/services/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/services/interpreter.service.ts b/zeppelin-web-angular/src/app/services/interpreter.service.ts new file mode 100644 index 00000000000..82f93bbfae4 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/interpreter.service.ts @@ -0,0 +1,84 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { + CreateInterpreterRepositoryForm, + Interpreter, + InterpreterMap, + InterpreterPropertyTypes, + InterpreterRepository +} from '@zeppelin/interfaces'; +import { InterpreterItem } from '@zeppelin/sdk'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class InterpreterService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getRepositories() { + return this.http.get(this.restUrl`/interpreter/repository`); + } + + addRepository(repo: CreateInterpreterRepositoryForm) { + return this.http.post(this.restUrl`/interpreter/repository`, repo); + } + + removeRepository(repoId: string) { + return this.http.delete(this.restUrl`/interpreter/repository/${repoId}`); + } + + getInterpretersSetting() { + return this.http.get(this.restUrl`/interpreter/setting`); + } + + getAvailableInterpreters() { + return this.http.get(this.restUrl`/interpreter`); + } + + getAvailableInterpreterPropertyTypes() { + return this.http.get(this.restUrl`/interpreter/property/types`); + } + + addInterpreterSetting(interpreter: Interpreter) { + return this.http.post(this.restUrl`/interpreter/setting`, interpreter); + } + + updateInterpreter(interpreter: Interpreter) { + const { option, properties, dependencies } = interpreter; + return this.http.put(this.restUrl`/interpreter/setting/${interpreter.name}`, { + option, + properties, + dependencies + }); + } + + restartInterpreter(interpreterId: string, noteId: string) { + return this.http.put(this.restUrl`/interpreter/setting/restart/${interpreterId}`, { noteId }); + } + + removeInterpreterSetting(settingId: string) { + return this.http.delete(this.restUrl`/interpreter/setting/${settingId}`); + } + + restartInterpreterSetting(settingId: string) { + return this.http.put(this.restUrl`/interpreter/setting/restart/${settingId}`, null); + } +} diff --git a/zeppelin-web-angular/src/app/services/job-manager.service.ts b/zeppelin-web-angular/src/app/services/job-manager.service.ts new file mode 100644 index 00000000000..b61523219c2 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/job-manager.service.ts @@ -0,0 +1,34 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class JobManagerService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + startJob(noteId: string) { + return this.http.post(this.restUrl`/notebook/job/${noteId}`, {}); + } + + stopJob(noteId: string) { + return this.http.delete(this.restUrl`/notebook/job/${noteId}`, {}); + } +} diff --git a/zeppelin-web-angular/src/app/services/message.service.ts b/zeppelin-web-angular/src/app/services/message.service.ts new file mode 100644 index 00000000000..fd47803749f --- /dev/null +++ b/zeppelin-web-angular/src/app/services/message.service.ts @@ -0,0 +1,331 @@ +/* + * 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 { Inject, Injectable, OnDestroy, Optional } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { MessageInterceptor, MESSAGE_INTERCEPTOR } from '@zeppelin/interfaces'; +import { + Message, + MessageReceiveDataTypeMap, + MessageSendDataTypeMap, + NoteConfig, + ParagraphConfig, + ParagraphParams, + PersonalizedMode, + SendArgumentsType, + SendNote, + SendParagraph, + WebSocketMessage +} from '@zeppelin/sdk'; + +import { BaseUrlService } from './base-url.service'; +import { TicketService } from './ticket.service'; + +@Injectable({ + providedIn: 'root' +}) +export class MessageService extends Message implements OnDestroy { + constructor( + private baseUrlService: BaseUrlService, + private ticketService: TicketService, + @Optional() @Inject(MESSAGE_INTERCEPTOR) private messageInterceptor: MessageInterceptor + ) { + super(); + } + + interceptReceived( + data: WebSocketMessage + ): WebSocketMessage { + return this.messageInterceptor ? this.messageInterceptor.received(data) : super.interceptReceived(data); + } + + bootstrap(): void { + super.bootstrap(this.ticketService.originTicket, this.baseUrlService.getWebsocketUrl()); + } + + ping() { + super.ping(); + } + + closed(): Observable { + return super.closed(); + } + + sent(): Observable> { + return super.sent(); + } + + received(): Observable> { + return super.received(); + } + + send(...args: SendArgumentsType): void { + super.send(...args); + } + + receive(op: K): Observable[K]> { + return super.receive(op); + } + + opened(): Observable { + return super.opened(); + } + + ngOnDestroy(): void { + super.destroy(); + } + + getHomeNote(): void { + super.getHomeNote(); + } + + newNote(noteName: string, defaultInterpreterGroup: string): void { + super.newNote(noteName, defaultInterpreterGroup); + } + + moveNoteToTrash(noteId: string): void { + super.moveNoteToTrash(noteId); + } + + restoreNote(noteId: string): void { + super.restoreNote(noteId); + } + + deleteNote(noteId): void { + super.deleteNote(noteId); + } + + restoreFolder(folderPath: string): void { + super.restoreFolder(folderPath); + } + + removeFolder(folderPath: string): void { + super.removeFolder(folderPath); + } + + moveFolderToTrash(folderPath: string): void { + super.moveFolderToTrash(folderPath); + } + + restoreAll(): void { + super.restoreAll(); + } + + emptyTrash(): void { + super.emptyTrash(); + } + + cloneNote(noteIdToClone, newNoteName): void { + super.cloneNote(noteIdToClone, newNoteName); + } + + listNodes(): void { + super.listNodes(); + } + + reloadAllNotesFromRepo(): void { + super.reloadAllNotesFromRepo(); + } + + getNote(noteId: string): void { + super.getNote(noteId); + } + + updateNote(noteId: string, noteName: string, noteConfig: NoteConfig): void { + super.updateNote(noteId, noteName, noteConfig); + } + + updatePersonalizedMode(noteId: string, modeValue: PersonalizedMode): void { + super.updatePersonalizedMode(noteId, modeValue); + } + + noteRename(noteId: string, noteName: string, relative?: boolean): void { + super.noteRename(noteId, noteName, relative); + } + + folderRename(folderId: string, folderPath: string): void { + super.folderRename(folderId, folderPath); + } + + moveParagraph(paragraphId: string, newIndex: number): void { + super.moveParagraph(paragraphId, newIndex); + } + + insertParagraph(newIndex: number): void { + super.insertParagraph(newIndex); + } + + copyParagraph( + newIndex: number, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + super.copyParagraph(newIndex, paragraphTitle, paragraphData, paragraphConfig, paragraphParams); + } + + angularObjectUpdate( + noteId: string, + paragraphId: string, + name: string, + value: string, + interpreterGroupId: string + ): void { + super.angularObjectUpdate(noteId, paragraphId, name, value, interpreterGroupId); + } + + // tslint:disable-next-line:no-any + angularObjectClientBind(noteId: string, name: string, value: any, paragraphId: string): void { + super.angularObjectClientBind(noteId, name, value, paragraphId); + } + + angularObjectClientUnbind(noteId: string, name: string, paragraphId: string): void { + super.angularObjectClientUnbind(noteId, name, paragraphId); + } + + cancelParagraph(paragraphId): void { + super.cancelParagraph(paragraphId); + } + + paragraphExecutedBySpell( + paragraphId, + paragraphTitle, + paragraphText, + paragraphResultsMsg, + paragraphStatus, + paragraphErrorMessage, + paragraphConfig, + paragraphParams, + paragraphDateStarted, + paragraphDateFinished + ): void { + super.paragraphExecutedBySpell( + paragraphId, + paragraphTitle, + paragraphText, + paragraphResultsMsg, + paragraphStatus, + paragraphErrorMessage, + paragraphConfig, + paragraphParams, + paragraphDateStarted, + paragraphDateFinished + ); + } + + runParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphParams + ): void { + super.runParagraph(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams); + } + + runAllParagraphs(noteId: string, paragraphs: SendParagraph[]): void { + super.runAllParagraphs(noteId, paragraphs); + } + + paragraphRemove(paragraphId: string): void { + super.paragraphRemove(paragraphId); + } + + paragraphClearOutput(paragraphId: string): void { + super.paragraphClearOutput(paragraphId); + } + + paragraphClearAllOutput(noteId: string): void { + super.paragraphClearAllOutput(noteId); + } + + completion(paragraphId: string, buf: string, cursor: number): void { + super.completion(paragraphId, buf, cursor); + } + + commitParagraph( + paragraphId: string, + paragraphTitle: string, + paragraphData: string, + paragraphConfig: ParagraphConfig, + paragraphParams: ParagraphConfig, + noteId: string + ): void { + super.commitParagraph(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams, noteId); + } + + patchParagraph(paragraphId: string, noteId: string, patch: string): void { + super.patchParagraph(paragraphId, noteId, patch); + } + + importNote(note: SendNote): void { + super.importNote(note); + } + + checkpointNote(noteId: string, commitMessage: string): void { + super.checkpointNote(noteId, commitMessage); + } + + setNoteRevision(noteId: string, revisionId: string): void { + super.setNoteRevision(noteId, revisionId); + } + + listRevisionHistory(noteId: string): void { + super.listRevisionHistory(noteId); + } + + noteRevision(noteId: string, revisionId: string): void { + super.noteRevision(noteId, revisionId); + } + + noteRevisionForCompare(noteId: string, revisionId: string, position: string): void { + super.noteRevisionForCompare(noteId, revisionId, position); + } + + editorSetting(paragraphId: string, replName: string): void { + super.editorSetting(paragraphId, replName); + } + + listNoteJobs(): void { + super.listNoteJobs(); + } + + unsubscribeUpdateNoteJobs(): void { + super.unsubscribeUpdateNoteJobs(); + } + + getInterpreterBindings(noteId: string): void { + super.getInterpreterBindings(noteId); + } + + saveInterpreterBindings(noteId, selectedSettingIds): void { + super.saveInterpreterBindings(noteId, selectedSettingIds); + } + + listConfigurations(): void { + super.listConfigurations(); + } + + getInterpreterSettings(): void { + super.getInterpreterSettings(); + } + + saveNoteForms(note: SendNote): void { + super.saveNoteForms(note); + } + + removeNoteForms(note, formName): void { + super.removeNoteForms(note, formName); + } +} diff --git a/zeppelin-web-angular/src/app/services/ng-z.service.ts b/zeppelin-web-angular/src/app/services/ng-z.service.ts new file mode 100644 index 00000000000..fe1ad9917d3 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/ng-z.service.ts @@ -0,0 +1,85 @@ +/* + * 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 { Injectable, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class NgZService implements OnDestroy { + private paragraphMap = new Map(); + private contextChange$ = new Subject<{ + paragraphId: string; + key: string; + // tslint:disable-next-line:no-any + value: any; + emit: boolean; + set: boolean; + }>(); + private runParagraph$ = new Subject(); + + constructor() {} + + contextChanged() { + return this.contextChange$.asObservable(); + } + + runParagraphAction() { + return this.runParagraph$.asObservable(); + } + + removeParagraph(paragraphId: string) { + this.paragraphMap.delete(paragraphId); + } + + runParagraph(paragraphId: string) { + this.runParagraph$.next(paragraphId); + } + + bindParagraph(paragraphId: string, context: {}) { + this.paragraphMap.set(paragraphId, context); + } + + setContextValue(key: string, value, paragraphId: string, emit = true) { + const context = this.paragraphMap.get(paragraphId); + if (context) { + context[key] = value; + } + this.contextChange$.next({ + paragraphId, + key, + value, + emit, + set: true + }); + } + + unsetContextValue(key: string, paragraphId: string, emit = true) { + const context = this.paragraphMap.get(paragraphId); + if (context) { + context[key] = undefined; + } + this.contextChange$.next({ + paragraphId, + key, + emit, + value: undefined, + set: false + }); + } + + ngOnDestroy(): void { + this.paragraphMap.clear(); + this.contextChange$.complete(); + } +} diff --git a/zeppelin-web-angular/src/app/services/note-action.service.ts b/zeppelin-web-angular/src/app/services/note-action.service.ts new file mode 100644 index 00000000000..8a2bd102841 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-action.service.ts @@ -0,0 +1,72 @@ +/* + * 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 { Injectable } from '@angular/core'; + +import { NzModalService } from 'ng-zorro-antd'; + +import { FolderRenameComponent } from '@zeppelin/share/folder-rename/folder-rename.component'; +import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; +import { NoteImportComponent } from '@zeppelin/share/note-import/note-import.component'; +import { NoteRenameComponent } from '@zeppelin/share/note-rename/note-rename.component'; + +@Injectable({ + providedIn: 'root' +}) +export class NoteActionService { + renameNote(id: string, path: string, name: string) { + this.nzModalService.create({ + nzTitle: 'Rename note', + nzContent: NoteRenameComponent, + nzComponentParams: { + id, + newName: path || name + }, + nzWidth: '800px', + nzFooter: null + }); + } + + renameFolder(path: string) { + this.nzModalService.create({ + nzTitle: 'Rename folder', + nzContent: FolderRenameComponent, + nzComponentParams: { + folderId: path, + newFolderPath: path + }, + nzWidth: '800px', + nzFooter: null + }); + } + + importNote() { + this.nzModalService.create({ + nzTitle: 'Import New Note', + nzContent: NoteImportComponent, + nzWidth: '800px', + nzFooter: null + }); + } + + createNote(path?: string) { + this.nzModalService.create({ + nzTitle: 'Create New Note', + nzContent: NoteCreateComponent, + nzComponentParams: { path }, + nzWidth: '800px', + nzFooter: null + }); + } + + constructor(private nzModalService: NzModalService) {} +} diff --git a/zeppelin-web-angular/src/app/services/note-list.service.ts b/zeppelin-web-angular/src/app/services/note-list.service.ts new file mode 100644 index 00000000000..83070b51148 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-list.service.ts @@ -0,0 +1,97 @@ +/* + * 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 { Inject, Injectable } from '@angular/core'; + +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { NotesInfoItem } from '@zeppelin/sdk'; + +import { NodeList } from '../interfaces/node-list'; +import { ArrayOrderingService } from './array-ordering.service'; + +@Injectable({ + providedIn: 'root' +}) +export class NoteListService { + notes: NodeList = { + root: { children: [] }, + flatList: [], + flatFolderMap: {} + }; + + setNotes(notesList: NotesInfoItem[]) { + // a flat list to boost searching + this.notes.flatList = notesList.map(note => { + const isTrash = note.path ? note.path.split('/')[1] === this.TRASH_FOLDER_ID : false; + return { ...note, isTrash }; + }); + + // construct the folder-based tree + this.notes.root = { children: [] }; + this.notes.flatFolderMap = {}; + notesList.reduce((root, note) => { + const notePath = note.path || note.id; + const nodes = notePath.match(/([^\/][^\/]*)/g); + + // recursively add nodes + this.addNode(root, nodes, note.id); + + return root; + }, this.notes.root); + this.notes.root.children.sort(this.arrayOrderingService.noteComparator); + } + + addNode(curDir, nodes, noteId) { + if (nodes.length === 1) { + // the leaf + curDir.children.push({ + id: noteId, + title: nodes[0], + isLeaf: true, + nodeType: 'note', + path: curDir.id ? `${curDir.id}/${nodes[0]}` : nodes[0], + isTrash: curDir.id ? curDir.id.split('/')[0] === this.TRASH_FOLDER_ID : false + }); + } else { + // a folder node + const node = nodes.shift(); + const dir = curDir.children.find(c => { + return c.title === node && c.children !== undefined; + }); + if (dir !== undefined) { + // found an existing dir + this.addNode(dir, nodes, noteId); + } else { + const id = curDir.id ? `${curDir.id}/${node}` : node; + const newDir = { + id, + title: node, + expanded: false, + nodeType: id === this.TRASH_FOLDER_ID ? 'trash' : 'folder', + children: [], + isTrash: curDir.id ? curDir.id.split('/')[0] === this.TRASH_FOLDER_ID : false + }; + + // add the folder to flat folder map + this.notes.flatFolderMap[newDir.id] = newDir; + + curDir.children.push(newDir); + this.addNode(newDir, nodes, noteId); + } + } + } + + constructor( + @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, + private arrayOrderingService: ArrayOrderingService + ) {} +} diff --git a/zeppelin-web-angular/src/app/services/note-status.service.ts b/zeppelin-web-angular/src/app/services/note-status.service.ts new file mode 100644 index 00000000000..e5ff4a90bb6 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-status.service.ts @@ -0,0 +1,65 @@ +/* + * 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 { Inject, Injectable } from '@angular/core'; + +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; +import { Note, ParagraphItem } from '@zeppelin/sdk'; + +export const ParagraphStatus = { + READY: 'READY', + PENDING: 'PENDING', + RUNNING: 'RUNNING', + FINISHED: 'FINISHED', + ABORT: 'ABORT', + ERROR: 'ERROR' +}; + +@Injectable({ + providedIn: 'root' +}) +export class NoteStatusService { + isParagraphRunning(paragraph: ParagraphItem) { + if (!paragraph) { + return false; + } + const status = paragraph.status; + if (!status) { + return false; + } + + return status === ParagraphStatus.PENDING || status === ParagraphStatus.RUNNING; + } + + isTrash(note: Note['note']) { + // TODO(hsuanxyz) https://github.com/apache/zeppelin/pull/3365/files + return note.name.split('/')[1] === this.TRASH_FOLDER_ID; + } + + viewOnly(note: Note['note']): boolean { + return note.config.looknfeel === 'report'; + } + + isNoteParagraphRunning(note: Note['note']): boolean { + if (!note) { + return false; + } else { + return note.paragraphs.some(p => this.isParagraphRunning(p)); + } + } + + isEntireNoteRunning(note: Note['note']): boolean { + return !!(note.info && note.info.isRunning && note.info.isRunning === true); + } + + constructor(@Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string) {} +} diff --git a/zeppelin-web-angular/src/app/services/note-var-share.service.ts b/zeppelin-web-angular/src/app/services/note-var-share.service.ts new file mode 100644 index 00000000000..edb7bed7fb4 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/note-var-share.service.ts @@ -0,0 +1,38 @@ +/* + * 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 { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class NoteVarShareService { + private store = new Map(); + + clear() { + this.store.clear(); + } + + set(key, value) { + this.store.set(key, value); + } + + get(key) { + return this.store.get(key); + } + + del(key) { + return this.store.delete(key); + } + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts new file mode 100644 index 00000000000..d56ec7e5c6f --- /dev/null +++ b/zeppelin-web-angular/src/app/services/public-api.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +export * from './base-url.service'; +export * from './ticket.service'; +export * from './message.service'; +export * from './job-manager.service'; +export * from './interpreter.service'; +export * from './security.service'; +export * from './note-status.service'; +export * from './save-as.service'; +export * from './helium.service'; +export * from './note-var-share.service'; +export * from './note-action.service'; +export * from './completion.service'; +export * from './ng-z.service'; +export * from './array-ordering.service'; +export * from './note-list.service'; +export * from './runtime-compiler.service'; diff --git a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts new file mode 100644 index 00000000000..9c91b697bca --- /dev/null +++ b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts @@ -0,0 +1,74 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { + Compiler, + Component, + Injectable, + ModuleWithComponentFactories, + NgModule, + NgModuleFactory, + Type +} from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { NgZorroAntdModule } from 'ng-zorro-antd'; + +import { NgZService } from './ng-z.service'; + +export class DynamicTemplate { + constructor( + public readonly template: string, + // tslint:disable-next-line:no-any + public readonly component: Type, + // tslint:disable-next-line:no-any + public readonly moduleFactory?: NgModuleFactory + ) {} +} + +@Injectable({ + providedIn: 'root' +}) +export class RuntimeCompilerService { + // tslint:disable-next-line:no-any + private compiledModule?: ModuleWithComponentFactories; + + public async createAndCompileTemplate(paragraphId: string, template: string): Promise { + const ngZService = this.ngZService; + const dynamicComponent = Component({ template: template })( + class DynamicTemplateComponent { + z = { + set: (key: string, value, id: string) => ngZService.setContextValue(key, value, id), + unset: (key: string, id: string) => ngZService.unsetContextValue(key, id), + run: (id: string) => ngZService.runParagraph(id) + }; + + constructor() { + ngZService.bindParagraph(paragraphId, this); + Object.freeze(this.z); + } + } + ); + const dynamicModule = NgModule({ + declarations: [dynamicComponent], + exports: [dynamicComponent], + entryComponents: [dynamicComponent], + imports: [CommonModule, NgZorroAntdModule, FormsModule] + })(class DynamicModule {}); + + this.compiledModule = await this.compiler.compileModuleAndAllComponentsAsync(dynamicModule); + return new DynamicTemplate(template, dynamicComponent, this.compiledModule.ngModuleFactory); + } + + constructor(private compiler: Compiler, private ngZService: NgZService) {} +} diff --git a/zeppelin-web-angular/src/app/services/save-as.service.ts b/zeppelin-web-angular/src/app/services/save-as.service.ts new file mode 100644 index 00000000000..53dc05c9bdd --- /dev/null +++ b/zeppelin-web-angular/src/app/services/save-as.service.ts @@ -0,0 +1,37 @@ +/* + * 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 { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class SaveAsService { + saveAs(content: string, filename: string, extension: string) { + const BOM = '\uFEFF'; + const fileName = `${filename}.${extension}`; + const binaryData = []; + binaryData.push(BOM); + binaryData.push(content); + const blob = new Blob(binaryData, { type: 'octet/stream' }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + document.body.appendChild(a); + a.style.display = 'none'; + a.href = url; + a.download = fileName; + a.click(); + window.URL.revokeObjectURL(url); + } + + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/services/security.service.ts b/zeppelin-web-angular/src/app/services/security.service.ts new file mode 100644 index 00000000000..c267ad05fa8 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/security.service.ts @@ -0,0 +1,40 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { Permissions, SecurityUserList } from '@zeppelin/interfaces'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class SecurityService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + searchUsers(term: string) { + return this.http.get(this.restUrl`/security/userlist/${term}`); + } + + getPermissions(id: string) { + return this.http.get(this.restUrl`/notebook/${id}/permissions`); + } + + setPermissions(id: string, permissions: Permissions) { + return this.http.put(this.restUrl`/notebook/${id}/permissions`, permissions); + } +} diff --git a/zeppelin-web-angular/src/app/services/ticket.service.ts b/zeppelin-web-angular/src/app/services/ticket.service.ts new file mode 100644 index 00000000000..9254cdc6ee7 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/ticket.service.ts @@ -0,0 +1,116 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; +import { forkJoin, BehaviorSubject, Subject } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; + +import { NzMessageService } from 'ng-zorro-antd'; + +import { ITicket, ITicketWrapped, IZeppelinVersion } from '@zeppelin/interfaces'; +import { ConfigurationsInfo } from '@zeppelin/sdk'; + +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class TicketService { + configuration: ConfigurationsInfo['configurations']; + ticket = new ITicketWrapped(); + originTicket = new ITicket(); + ticket$ = new Subject(); + logout$ = new BehaviorSubject(false); + version: string; + + setConfiguration(conf: ConfigurationsInfo) { + this.configuration = conf.configurations; + } + + getTicket() { + return forkJoin([ + this.httpClient.get(`${this.baseUrlService.getRestApiBase()}/security/ticket`), + this.getZeppelinVersion() + ]).pipe( + tap(data => { + const [ticket, version] = data; + this.version = version; + this.setTicket(ticket); + }) + ); + } + + setTicket(ticket: ITicket) { + if (ticket.redirectURL) { + window.location.href = ticket.redirectURL + window.location.href; + } + let screenUsername = ticket.principal; + if (ticket.principal.indexOf('#Pac4j') === 0) { + const re = ', name=(.*?),'; + screenUsername = ticket.principal.match(re)[1]; + } + this.originTicket = ticket; + this.ticket = { ...ticket, screenUsername, ...{ init: true } }; + this.ticket$.next(this.ticket); + } + + clearTicket() { + this.ticket = new ITicketWrapped(); + this.originTicket = new ITicket(); + } + + logout() { + this.logout$.next(true); + const nextAction = () => { + this.nzMessageService.success('Logout Success'); + this.clearTicket(); + this.logout$.next(false); + this.router.navigate(['/login']).then(); + }; + return this.httpClient + .post(`${this.baseUrlService.getRestApiBase()}/login/logout`, {}) + .pipe(tap(() => nextAction(), () => nextAction())); + } + + login(userName: string, password: string) { + return this.httpClient + .post(`${this.baseUrlService.getRestApiBase()}/login`, `password=${password}&userName=${userName}`, { + headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + }) + .pipe( + tap( + data => { + this.nzMessageService.success('Login Success'); + this.setTicket(data); + }, + () => { + this.nzMessageService.warning("The username and password that you entered don't match."); + } + ) + ); + } + + getZeppelinVersion() { + return this.httpClient + .get(`${this.baseUrlService.getRestApiBase()}/version`) + .pipe(map(data => data.version)); + } + + constructor( + private httpClient: HttpClient, + private baseUrlService: BaseUrlService, + private router: Router, + private nzMessageService: NzMessageService + ) {} +} diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html new file mode 100644 index 00000000000..c7d8cc5d73c --- /dev/null +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html @@ -0,0 +1,28 @@ + + + diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less new file mode 100644 index 00000000000..73be35e8bc8 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.less @@ -0,0 +1,38 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .modal { + .about-logo { + img { + width: 95%; + } + } + + .content { + text-align: center; + + h3 { + font-family: 'Patua One', cursive; + color: #3071A9; + font-size: 30px; + margin: 0 auto; + } + + .about-version { + font-weight: 500; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts new file mode 100644 index 00000000000..41e8e777324 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.ts @@ -0,0 +1,26 @@ +/* + * 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 { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-about-zeppelin', + templateUrl: './about-zeppelin.component.html', + styleUrls: ['./about-zeppelin.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AboutZeppelinComponent implements OnInit { + constructor(public ticketService: TicketService) {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html new file mode 100644 index 00000000000..1b40367eb04 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.html @@ -0,0 +1,19 @@ + + +
+ +
+ +
+ +
diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts new file mode 100644 index 00000000000..2fdbaa5950d --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.component.ts @@ -0,0 +1,244 @@ +/* + * 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 { + forwardRef, + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + EventEmitter, + Input, + NgZone, + OnDestroy, + Output, + TemplateRef, + ViewEncapsulation +} from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { combineLatest, fromEvent, BehaviorSubject, Subject } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, map, takeUntil } from 'rxjs/operators'; + +import { warn, InputBoolean } from 'ng-zorro-antd/core'; + +import { CodeEditorService } from './code-editor.service'; +import { DiffEditorOptions, EditorOptions, JoinedEditorOptions, NzEditorMode } from './nz-code-editor.definitions'; + +// Import types from monaco editor. +import { editor } from 'monaco-editor'; +import IEditor = editor.IEditor; +import IDiffEditor = editor.IDiffEditor; +import ITextModel = editor.ITextModel; + +@Component({ + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + selector: 'zeppelin-code-editor', + exportAs: 'CodeEditor', + templateUrl: './code-editor.component.html', + host: { + '[class.ant-code-editor]': 'true' + }, + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CodeEditorComponent), + multi: true + } + ] +}) +export class CodeEditorComponent implements OnDestroy, AfterViewInit { + @Input() nzEditorMode: NzEditorMode = 'normal'; + @Input() nzOriginalText = ''; + @Input() @InputBoolean() nzLoading = false; + @Input() @InputBoolean() nzFullControl = false; + @Input() nzToolkit: TemplateRef; + + @Input() set nzEditorOption(value: JoinedEditorOptions) { + this.editorOption$.next(value); + } + + @Output() readonly nzEditorInitialized = new EventEmitter(); + + editorOptionCached: JoinedEditorOptions = {}; + + private readonly el: HTMLElement; + private destroy$ = new Subject(); + private resize$ = new Subject(); + private editorOption$ = new BehaviorSubject({}); + private editorInstance: IEditor | IDiffEditor; + private value = ''; + private modelSet = false; + + constructor(private nzCodeEditorService: CodeEditorService, private ngZone: NgZone, elementRef: ElementRef) { + this.el = elementRef.nativeElement; + } + + /** + * Initialize a monaco editor instance. + */ + ngAfterViewInit(): void { + this.nzCodeEditorService.requestToInit().subscribe(option => this.setup(option)); + } + + ngOnDestroy(): void { + if (this.editorInstance) { + this.editorInstance.dispose(); + } + + this.destroy$.next(); + this.destroy$.complete(); + } + + writeValue(value: string): void { + this.value = value; + this.setValue(); + } + + // tslint:disable-next-line no-any + registerOnChange(fn: (value: string) => void): any { + this.onChange = fn; + } + + // tslint:disable-next-line no-any + registerOnTouched(fn: any): void { + this.onTouch = fn; + } + + onChange(_value: string): void {} + + onTouch(): void {} + + layout(): void { + this.resize$.next(); + } + + private setup(option: JoinedEditorOptions): void { + this.editorOptionCached = option; + this.registerOptionChanges(); + this.initMonacoEditorInstance(); + this.registerResizeChange(); + this.setValue(); + + if (!this.nzFullControl) { + this.setValueEmitter(); + } + this.nzEditorInitialized.emit(this.editorInstance); + } + + private registerOptionChanges(): void { + combineLatest([this.editorOption$, this.nzCodeEditorService.option$]) + .pipe(takeUntil(this.destroy$)) + .subscribe(([selfOpt, defaultOpt]) => { + this.editorOptionCached = { + ...this.editorOptionCached, + ...defaultOpt, + ...selfOpt + }; + this.updateOptionToMonaco(); + }); + } + + private initMonacoEditorInstance(): void { + this.ngZone.runOutsideAngular(() => { + this.editorInstance = + this.nzEditorMode === 'normal' + ? editor.create(this.el, { ...this.editorOptionCached }) + : editor.createDiffEditor(this.el, { + ...(this.editorOptionCached as DiffEditorOptions) + }); + }); + } + + private registerResizeChange(): void { + this.ngZone.runOutsideAngular(() => { + fromEvent(window, 'resize') + .pipe( + debounceTime(300), + takeUntil(this.destroy$) + ) + .subscribe(() => { + this.layout(); + }); + + this.resize$ + .pipe( + takeUntil(this.destroy$), + filter(() => !!this.editorInstance), + map(() => ({ + width: this.el.clientWidth, + height: this.el.clientHeight + })), + distinctUntilChanged((a, b) => a.width === b.width && a.height === b.height), + debounceTime(50) + ) + .subscribe(() => { + this.editorInstance.layout(); + }); + }); + } + + private setValue(): void { + if (!this.editorInstance) { + return; + } + + if (this.nzFullControl && this.value) { + warn(`should not set value when you are using full control mode! It would result in ambiguous data flow!`); + return; + } + + if (this.nzEditorMode === 'normal') { + if (this.modelSet) { + (this.editorInstance.getModel() as ITextModel).setValue(this.value); + } else { + (this.editorInstance as IEditor).setModel( + editor.createModel(this.value, (this.editorOptionCached as EditorOptions).language) + ); + this.modelSet = true; + } + } else { + if (this.modelSet) { + const model = (this.editorInstance as IDiffEditor).getModel()!; + model.modified.setValue(this.value); + model.original.setValue(this.nzOriginalText); + } else { + const language = (this.editorOptionCached as EditorOptions).language; + (this.editorInstance as IDiffEditor).setModel({ + original: editor.createModel(this.value, language), + modified: editor.createModel(this.nzOriginalText, language) + }); + } + } + } + + private setValueEmitter(): void { + const model = (this.nzEditorMode === 'normal' + ? (this.editorInstance as IEditor).getModel() + : (this.editorInstance as IDiffEditor).getModel()!.modified) as ITextModel; + + model.onDidChangeContent(() => { + this.emitValue(model.getValue()); + }); + } + + private emitValue(value: string): void { + this.value = value; + this.onChange(value); + } + + private updateOptionToMonaco(): void { + if (this.editorInstance) { + this.editorInstance.updateOptions({ ...this.editorOptionCached }); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts b/zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts new file mode 100644 index 00000000000..6af049bc1b4 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.module.ts @@ -0,0 +1,26 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzSpinModule } from 'ng-zorro-antd/spin'; + +import { CodeEditorComponent } from './code-editor.component'; + +@NgModule({ + declarations: [CodeEditorComponent], + imports: [CommonModule, NzIconModule, NzSpinModule], + exports: [CodeEditorComponent] +}) +export class CodeEditorModule {} diff --git a/zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts b/zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts new file mode 100644 index 00000000000..f24d9ec4d89 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/code-editor.service.ts @@ -0,0 +1,104 @@ +/* + * 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 { DOCUMENT } from '@angular/common'; +import { Inject, Injectable } from '@angular/core'; +import { of as observableOf, BehaviorSubject, Observable, Subject } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; + +import { + JoinedEditorOptions, + NzCodeEditorConfig, + NzCodeEditorLoadingStatus, + NZ_CODE_EDITOR_CONFIG +} from './nz-code-editor.definitions'; + +import { editor } from 'monaco-editor'; + +// tslint:disable no-any +function tryTriggerFunc(fn?: (...args: any[]) => any): (...args: any) => void { + return (...args: any[]) => { + if (fn) { + fn(...args); + } + }; +} +// tslint:enable no-any + +@Injectable({ + providedIn: 'root' +}) +export class CodeEditorService { + private document: Document; + private firstEditorInitialized = false; + private loaded$ = new Subject(); + private loadingStatus = NzCodeEditorLoadingStatus.UNLOAD; + private option: JoinedEditorOptions; + + option$ = new BehaviorSubject(this.option); + + constructor( + @Inject(NZ_CODE_EDITOR_CONFIG) private config: NzCodeEditorConfig, + @Inject(DOCUMENT) _document: any // tslint:disable-line no-any + ) { + this.document = _document; + this.option = this.config.defaultEditorOption || {}; + } + + // TODO(hsuanxyz): use config service later. + updateDefaultOption(option: JoinedEditorOptions): void { + this.option = { ...this.option, ...option }; + this.option$.next(this.option); + + if (option.theme) { + editor.setTheme(option.theme); + } + } + + requestToInit(): Observable { + if (this.loadingStatus === NzCodeEditorLoadingStatus.LOADED) { + this.onInit(); + return observableOf(this.getLatestOption()); + } + + if (this.loadingStatus === NzCodeEditorLoadingStatus.UNLOAD) { + this.loadingStatus = NzCodeEditorLoadingStatus.LOADED; + this.loaded$.next(true); + this.loaded$.complete(); + this.onLoad(); + this.onInit(); + return observableOf(this.getLatestOption()); + } + + return this.loaded$.asObservable().pipe( + tap(() => this.onInit()), + map(() => this.getLatestOption()) + ); + } + + private onInit(): void { + if (!this.firstEditorInitialized) { + this.firstEditorInitialized = true; + tryTriggerFunc(this.config.onFirstEditorInit)(); + } + + tryTriggerFunc(this.config.onInit)(); + } + + private onLoad(): void { + tryTriggerFunc(this.config.onLoad)(); + } + + private getLatestOption(): JoinedEditorOptions { + return { ...this.option }; + } +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/index.ts b/zeppelin-web-angular/src/app/share/code-editor/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts b/zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts new file mode 100644 index 00000000000..103b10db1d4 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/nz-code-editor.definitions.ts @@ -0,0 +1,46 @@ +/* + * 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 { InjectionToken } from '@angular/core'; +import { SafeUrl } from '@angular/platform-browser'; +import { editor } from 'monaco-editor'; +import IEditorConstructionOptions = editor.IEditorConstructionOptions; +import IDiffEditorConstructionOptions = editor.IDiffEditorConstructionOptions; + +export type EditorOptions = IEditorConstructionOptions; +export type DiffEditorOptions = IDiffEditorConstructionOptions; +export type JoinedEditorOptions = EditorOptions | DiffEditorOptions; + +export type NzEditorMode = 'normal' | 'diff'; + +export enum NzCodeEditorLoadingStatus { + UNLOAD = 'unload', + LOADING = 'loading', + LOADED = 'LOADED' +} + +export interface NzCodeEditorConfig { + assetsRoot?: string | SafeUrl; + defaultEditorOption?: JoinedEditorOptions; + onLoad?(): void; + onFirstEditorInit?(): void; + onInit?(): void; +} + +export const NZ_CODE_EDITOR_CONFIG = new InjectionToken('nz-code-editor-config', { + providedIn: 'root', + factory: NZ_CODE_EDITOR_CONFIG_FACTORY +}); + +export function NZ_CODE_EDITOR_CONFIG_FACTORY(): NzCodeEditorConfig { + return {}; +} diff --git a/zeppelin-web-angular/src/app/share/code-editor/public-api.ts b/zeppelin-web-angular/src/app/share/code-editor/public-api.ts new file mode 100644 index 00000000000..b2144c936c7 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/code-editor/public-api.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ + +export * from './nz-code-editor.definitions'; +export * from './code-editor.component'; +export * from './code-editor.module'; +export * from './code-editor.service'; diff --git a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html new file mode 100644 index 00000000000..71c4eac1a72 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.html @@ -0,0 +1,32 @@ + + +
+ + Please enter a new name + + + + + + + + + + +
+ + + The folder will be merged into {{newFolderPath}}. Are you sure? + diff --git a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts new file mode 100644 index 00000000000..250dac36854 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts @@ -0,0 +1,80 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { NzModalRef } from 'ng-zorro-antd'; + +import { MessageService } from '@zeppelin/services/message.service'; +import { NoteListService } from '@zeppelin/services/note-list.service'; + +@Component({ + selector: 'zeppelin-folder-rename', + templateUrl: './folder-rename.component.html', + styleUrls: ['./folder-rename.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FolderRenameComponent implements OnInit { + @Input() newFolderPath: string; + @Input() folderId: string; + willMerged = false; + + checkMerged() { + const newFolderPath = this.normalizeFolderId(this.newFolderPath); + this.willMerged = this.folderId !== this.newFolderPath && !!this.noteListService.notes.flatFolderMap[newFolderPath]; + this.cdr.markForCheck(); + } + + rename() { + this.messageService.folderRename(this.folderId, this.newFolderPath); + this.nzModalRef.destroy(); + } + + normalizeFolderId(folderId) { + let normalizeFolderId = folderId.trim(); + + while (normalizeFolderId.indexOf('\\') > -1) { + normalizeFolderId = normalizeFolderId.replace('\\', '/'); + } + + while (normalizeFolderId.indexOf('///') > -1) { + normalizeFolderId = normalizeFolderId.replace('///', '/'); + } + + normalizeFolderId = normalizeFolderId.replace('//', '/'); + + if (normalizeFolderId === '/') { + return '/'; + } + + if (normalizeFolderId[0] === '/') { + normalizeFolderId = normalizeFolderId.substring(1); + } + + if (normalizeFolderId.slice(-1) === '/') { + normalizeFolderId = normalizeFolderId.slice(0, -1); + } + + return normalizeFolderId; + } + + constructor( + private noteListService: NoteListService, + private cdr: ChangeDetectorRef, + private messageService: MessageService, + private nzModalRef: NzModalRef + ) {} + + ngOnInit() { + this.checkMerged(); + } +} diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html new file mode 100644 index 00000000000..71e8cd7c614 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/header/header.component.html @@ -0,0 +1,77 @@ + + +
+ + +
+ + + + + + + +
+ +
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.less b/zeppelin-web-angular/src/app/share/header/header.component.less new file mode 100644 index 00000000000..e4754b15ec9 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/header/header.component.less @@ -0,0 +1,110 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .small-icon { + margin-left: 6px; + font-size: 12px; + margin-right: 0; + transform: scale(0.8); + } + .node-list-trigger { + height: 100%; + display: inline-block; + margin: 0 -20px; + padding: 0 20px; + color: @text-color; + } + .header { + position: relative; + z-index: 999; + width: 100%; + height: 50px; + background: @component-background; + padding: 0 15px; + overflow: hidden; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.06) + } + .brand { + float: left; + width: 200px; + } + .logo { + height: 50px; + width: 75px; + background-size: 50px 30px; + background-repeat: no-repeat; + background-position: center; + background-image: url("../../../assets/images/zeppelin_svg_logo.svg"); + float: left; + } + .title { + float: left; + line-height: 50px; + font-family: 'Patua One', cursive; + font-size: 25px; + color: @primary-color; + } + .nav { + float: left; + + ul { + position: relative; + top: 2px; + border-bottom: none; + } + + a { + font-weight: 500; + } + } + .search { + float: right; + padding: 9px; + width: 300px; + margin-right: 24px; + } + .user { + float: right; + + .status { + line-height: 50px; + height: 50px; + display: inline-block; + color: @text-color; + } + } + .modal { + .about-logo { + img { + width: 95%; + } + } + + .content { + text-align: center; + + h3 { + font-family: 'Patua One', cursive; + color: #3071A9; + font-size: 30px; + margin: 0 auto; + } + + .about-version { + font-weight: 500; + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts new file mode 100644 index 00000000000..d9e4cc7e693 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/header/header.component.ts @@ -0,0 +1,86 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { NavigationEnd, Router } from '@angular/router'; +import { NzModalService } from 'ng-zorro-antd'; + +import { Subject } from 'rxjs'; +import { filter, takeUntil } from 'rxjs/operators'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk'; +import { MessageService, TicketService } from '@zeppelin/services'; +import { AboutZeppelinComponent } from '@zeppelin/share/about-zeppelin/about-zeppelin.component'; + +@Component({ + selector: 'zeppelin-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class HeaderComponent extends MessageListenersManager implements OnInit, OnDestroy { + private destroy$ = new Subject(); + connectStatus = 'error'; + noteListVisible = false; + + about() { + this.nzModalService.create({ + nzTitle: 'About Zeppelin', + nzWidth: '600px', + nzContent: AboutZeppelinComponent, + nzFooter: null + }); + } + + logout() { + this.ticketService.logout().subscribe(); + } + + @MessageListener(OP.CONFIGURATIONS_INFO) + getConfiguration(data: MessageReceiveDataTypeMap[OP.CONFIGURATIONS_INFO]) { + this.ticketService.setConfiguration(data); + } + + constructor( + public ticketService: TicketService, + private nzModalService: NzModalService, + public messageService: MessageService, + private router: Router, + private cdr: ChangeDetectorRef + ) { + super(messageService); + } + + ngOnInit() { + this.messageService.listConfigurations(); + this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(status => { + this.connectStatus = status ? 'success' : 'error'; + this.cdr.markForCheck(); + }); + this.router.events + .pipe( + filter(e => e instanceof NavigationEnd), + takeUntil(this.destroy$) + ) + .subscribe(() => { + this.noteListVisible = false; + this.cdr.markForCheck(); + }); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + super.ngOnDestroy(); + } +} diff --git a/zeppelin-web-angular/src/app/share/index.ts b/zeppelin-web-angular/src/app/share/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts b/zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts new file mode 100644 index 00000000000..7352122a8da --- /dev/null +++ b/zeppelin-web-angular/src/app/share/math-jax/math-jax.directive.ts @@ -0,0 +1,24 @@ +/* + * 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 { AfterViewChecked, Directive, ElementRef } from '@angular/core'; + +@Directive({ + selector: '[zeppelinMathJax]' +}) +export class MathJaxDirective implements AfterViewChecked { + constructor(private el: ElementRef) {} + + ngAfterViewChecked(): void { + MathJax.Hub.Queue(['Typeset', MathJax.Hub, this.el.nativeElement]); + } +} diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.html b/zeppelin-web-angular/src/app/share/node-list/node-list.component.html new file mode 100644 index 00000000000..70be6910499 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.html @@ -0,0 +1,139 @@ + + + diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.less b/zeppelin-web-angular/src/app/share/node-list/node-list.component.less new file mode 100644 index 00000000000..aec40c15ccf --- /dev/null +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.less @@ -0,0 +1,82 @@ +/* + * 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 'theme-mixin'; + +:host { + display: block; +} + +.themeMixin({ + .content { + width: 100%; + position: relative; + + &.header-mode { + .operation { + display: none; + } + } + } + .rename { + width: 200px; + } + nz-tree { + display: block; + } + nz-input-group { + width: 100%; + margin-top: 12px; + margin-bottom: 6px; + } + .node { + line-height: 24px; + display: inline-block; + width: calc(~"100% - 24px"); + + &.not-matched { + opacity: 0.5; + filter: grayscale(1); + } + + i { + margin-right: 6px; + } + + .operation { + margin-left: 12px; + + i { + font-size: 12px; + display: none; + + &:hover { + color: @link-active-color; + } + } + } + + &.active { + .name { + color: @link-active-color; + } + } + + &:hover, &.active { + .operation { + i { + display: inline-block; + } + } + } + } +}); diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts new file mode 100644 index 00000000000..c9206fd1fce --- /dev/null +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts @@ -0,0 +1,117 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { NzModalService, NzTreeNode } from 'ng-zorro-antd'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk'; +import { MessageService, NoteActionService, NoteListService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-node-list', + templateUrl: './node-list.component.html', + providers: [NoteListService], + styleUrls: ['./node-list.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NodeListComponent extends MessageListenersManager implements OnInit { + @Input() headerMode = false; + searchValue: string; + nodes = []; + activatedId: string; + + activeNote(id: string) { + this.activatedId = id; + } + + moveFolderToTrash(id: string) { + return this.messageService.moveFolderToTrash(id); + } + + restoreFolder(id: string) { + return this.messageService.restoreFolder(id); + } + + removeFolder(id: string) { + return this.messageService.removeFolder(id); + } + + paragraphClearAllOutput(id: string) { + return this.messageService.paragraphClearAllOutput(id); + } + + moveNoteToTrash(id: string) { + return this.messageService.moveNoteToTrash(id); + } + + restoreNote(id: string) { + return this.messageService.restoreNote(id); + } + + deleteNote(id: string) { + return this.messageService.deleteNote(id); + } + + restoreAll() { + return this.messageService.restoreAll(); + } + + emptyTrash() { + return this.messageService.emptyTrash(); + } + + toggleFolder(node: NzTreeNode) { + node.isExpanded = !node.isExpanded; + this.cdr.markForCheck(); + } + + renameNote(id: string, path: string, name: string) { + this.noteActionService.renameNote(id, path, name); + } + + renameFolder(path) { + this.noteActionService.renameFolder(path); + } + + importNote() { + this.noteActionService.importNote(); + } + + createNote(path?: string) { + this.noteActionService.createNote(path); + } + + @MessageListener(OP.NOTES_INFO) + getNotes(data: MessageReceiveDataTypeMap[OP.NOTES_INFO]) { + this.noteListService.setNotes(data.notes); + this.nodes = this.noteListService.notes.root.children.map(item => { + return { ...item, key: item.id }; + }); + this.cdr.markForCheck(); + } + + constructor( + private noteListService: NoteListService, + public messageService: MessageService, + private nzModalService: NzModalService, + private noteActionService: NoteActionService, + private cdr: ChangeDetectorRef + ) { + super(messageService); + } + + ngOnInit() { + this.messageService.listNodes(); + } +} diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.html b/zeppelin-web-angular/src/app/share/note-create/note-create.component.html new file mode 100644 index 00000000000..54fe7cde684 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.html @@ -0,0 +1,44 @@ + + +
+ + + Clone Note + Import As + + + + + + + Default Interpreter + + + + + + + + + + + + + +
+ diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.less b/zeppelin-web-angular/src/app/share/note-create/note-create.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts new file mode 100644 index 00000000000..42d9a95c91b --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts @@ -0,0 +1,105 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { NzModalRef } from 'ng-zorro-antd'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { InterpreterItem, MessageReceiveDataTypeMap, Note, OP } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services/message.service'; +import { NoteListService } from '@zeppelin/services/note-list.service'; + +@Component({ + selector: 'zeppelin-note-create', + templateUrl: './note-create.component.html', + styleUrls: ['./note-create.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteCreateComponent extends MessageListenersManager implements OnInit { + @Input() path: string; + @Input() cloneNote: Note['note']; + noteName: string; + defaultInterpreter: string; + listOfInterpreter: InterpreterItem[] = []; + + @MessageListener(OP.INTERPRETER_SETTINGS) + getInterpreterSettings(data: MessageReceiveDataTypeMap[OP.INTERPRETER_SETTINGS]) { + this.listOfInterpreter = data.interpreterSettings; + this.defaultInterpreter = data.interpreterSettings[0].name; + this.cdr.markForCheck(); + } + + @MessageListener(OP.NOTES_INFO) + getNotes() { + this.nzModalRef.destroy(); + } + + newNoteName(path: string) { + let newCount = 1; + this.noteListService.notes.flatList.forEach(note => { + const noteName = note.path; + if (noteName.match(/^\/Untitled Note [0-9]*$/)) { + const lastCount = +noteName.substr(15); + if (newCount <= lastCount) { + newCount = lastCount + 1; + } + } + }); + return `${path ? path + '/' : ''}Untitled Note ${newCount}`; + } + + cloneNoteName() { + let copyCount = 1; + let newCloneName = ''; + const lastIndex = this.cloneNote.name.lastIndexOf(' '); + const endsWithNumber: boolean = !!this.cloneNote.name.match('^.+?\\s\\d$'); + const noteNamePrefix = endsWithNumber ? this.cloneNote.name.substr(0, lastIndex) : this.cloneNote.name; + const regexp = new RegExp(`^${noteNamePrefix}.+`); + + this.noteListService.notes.flatList.forEach(note => { + const noteName = note.path; + if (noteName.match(regexp)) { + const lastCopyCount = parseInt(noteName.substr(lastIndex).trim(), 10); + newCloneName = noteNamePrefix; + if (copyCount <= lastCopyCount) { + copyCount = lastCopyCount + 1; + } + } + }); + + if (!newCloneName) { + newCloneName = this.cloneNote.name; + } + return `${newCloneName} ${copyCount}`; + } + + createNote() { + this.cloneNote + ? this.messageService.cloneNote(this.cloneNote.id, this.noteName) + : this.messageService.newNote(this.noteName, this.defaultInterpreter); + } + + constructor( + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private noteListService: NoteListService, + private nzModalRef: NzModalRef + ) { + super(messageService); + } + + ngOnInit() { + this.messageService.getInterpreterSettings(); + this.noteName = this.cloneNote ? this.cloneNoteName() : this.newNoteName(this.path); + } +} diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.html b/zeppelin-web-angular/src/app/share/note-import/note-import.component.html new file mode 100644 index 00000000000..861da357a90 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.html @@ -0,0 +1,50 @@ + + +
+ + Import As + + + + +
+ + + + +

+ +

+

Click or drag JSON file to this area to upload

+

+ JSON file size cannot exceed {{maxLimit | humanizeBytes}} +

+
+
+ +
+ + URL + + + + + + + + + +
+
+
+ diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.less b/zeppelin-web-angular/src/app/share/note-import/note-import.component.less new file mode 100644 index 00000000000..bb67745eec8 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.less @@ -0,0 +1,19 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + nz-alert { + margin-top: 12px; + } +}); diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts new file mode 100644 index 00000000000..4e928c957af --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts @@ -0,0 +1,110 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; + +import { get } from 'lodash'; +import { NzModalRef, UploadFile } from 'ng-zorro-antd'; + +import { MessageListener, MessageListenersManager } from '@zeppelin/core'; +import { OP } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services/message.service'; +import { TicketService } from '@zeppelin/services/ticket.service'; + +@Component({ + selector: 'zeppelin-note-import', + templateUrl: './note-import.component.html', + styleUrls: ['./note-import.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteImportComponent extends MessageListenersManager implements OnInit { + noteImportName: string; + importUrl: string; + errorText: string; + importLoading = false; + maxLimit = get(this.ticketService.configuration, ['zeppelin.websocket.max.text.message.size'], null); + + @MessageListener(OP.NOTES_INFO) + getNotes() { + this.nzModalRef.destroy(); + } + + importNote() { + this.errorText = ''; + this.importLoading = true; + this.httpClient.get(this.importUrl).subscribe( + data => { + this.importLoading = false; + this.processImportJson(data); + this.cdr.markForCheck(); + }, + () => { + this.errorText = 'Unable to Fetch URL'; + this.importLoading = false; + this.cdr.markForCheck(); + }, + () => {} + ); + } + + beforeUpload = (file: UploadFile): boolean => { + this.errorText = ''; + if (file.size > this.maxLimit) { + this.errorText = 'File size limit Exceeded!'; + } else { + const reader = new FileReader(); + // tslint:disable-next-line:no-any + reader.readAsText(file as any); + reader.onloadend = () => { + this.processImportJson(reader.result); + }; + } + this.cdr.markForCheck(); + return false; + }; + + processImportJson(data) { + let result = data; + if (typeof result !== 'object') { + try { + result = JSON.parse(result); + } catch (e) { + this.errorText = 'JSON parse exception'; + return; + } + } + if (result.paragraphs && result.paragraphs.length > 0) { + if (!this.noteImportName) { + this.noteImportName = result.name; + } else { + result.name = this.noteImportName; + } + this.messageService.importNote(result); + } else { + this.errorText = 'Invalid JSON'; + } + this.cdr.markForCheck(); + } + + constructor( + private ticketService: TicketService, + public messageService: MessageService, + private cdr: ChangeDetectorRef, + private nzModalRef: NzModalRef, + private httpClient: HttpClient + ) { + super(messageService); + } + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html new file mode 100644 index 00000000000..f37415e04c0 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.html @@ -0,0 +1,23 @@ + + +
+ + Please enter a new name + + + + + +
diff --git a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts new file mode 100644 index 00000000000..3b07b8d51b9 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts @@ -0,0 +1,37 @@ +/* + * 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 { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; + +import { NzModalRef } from 'ng-zorro-antd'; + +import { MessageService } from '@zeppelin/services/message.service'; + +@Component({ + selector: 'zeppelin-note-rename', + templateUrl: './note-rename.component.html', + styleUrls: ['./note-rename.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteRenameComponent implements OnInit { + @Input() newName: string; + @Input() id: string; + + rename() { + this.messageService.noteRename(this.id, this.newName); + this.nzModalRef.destroy(); + } + + constructor(private messageService: MessageService, private nzModalRef: NzModalRef) {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.html b/zeppelin-web-angular/src/app/share/page-header/page-header.component.html new file mode 100644 index 00000000000..430f7e2880b --- /dev/null +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.html @@ -0,0 +1,18 @@ + + + +

{{title}}

+

{{description}}

+ + +
diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.less b/zeppelin-web-angular/src/app/share/page-header/page-header.component.less new file mode 100644 index 00000000000..f0b6ac78b0e --- /dev/null +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.less @@ -0,0 +1,17 @@ +/* + * 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. + */ + +:host { + .header-extra { + float: right; + } +} diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts new file mode 100644 index 00000000000..1c03ee6298c --- /dev/null +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts @@ -0,0 +1,31 @@ +/* + * 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 { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core'; +import { InputBoolean } from 'ng-zorro-antd'; + +@Component({ + selector: 'zeppelin-page-header', + templateUrl: './page-header.component.html', + styleUrls: ['./page-header.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class PageHeaderComponent implements OnInit { + @Input() title: string; + @Input() description: string; + @Input() @InputBoolean() divider = false; + @Input() extra: TemplateRef; + + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts b/zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts new file mode 100644 index 00000000000..5460413af8e --- /dev/null +++ b/zeppelin-web-angular/src/app/share/pipes/humanize-bytes.pipe.ts @@ -0,0 +1,40 @@ +/* + * 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 { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'humanizeBytes' +}) +export class HumanizeBytesPipe implements PipeTransform { + transform(value: number): string { + if (value === null || value === undefined) { + return '-'; + } + const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB']; + const converter = (v: number, p: number): string => { + const base = Math.pow(1024, p); + if (v < base) { + return `${(v / base).toFixed(2)} ${units[p]}`; + } else if (v < base * 1000) { + return `${(v / base).toPrecision(3)} ${units[p]}`; + } else { + return converter(v, p + 1); + } + }; + if (value < 1000) { + return value + ' B'; + } else { + return converter(value, 1); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/pipes/index.ts b/zeppelin-web-angular/src/app/share/pipes/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/pipes/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/pipes/public-api.ts b/zeppelin-web-angular/src/app/share/pipes/public-api.ts new file mode 100644 index 00000000000..0397f58d260 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/pipes/public-api.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './humanize-bytes.pipe'; diff --git a/zeppelin-web-angular/src/app/share/public-api.ts b/zeppelin-web-angular/src/app/share/public-api.ts new file mode 100644 index 00000000000..b8c2732003e --- /dev/null +++ b/zeppelin-web-angular/src/app/share/public-api.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export * from './pipes'; +export * from './resize-handle'; +export * from './share.module'; diff --git a/zeppelin-web-angular/src/app/share/resize-handle/index.ts b/zeppelin-web-angular/src/app/share/resize-handle/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/resize-handle/public-api.ts b/zeppelin-web-angular/src/app/share/resize-handle/public-api.ts new file mode 100644 index 00000000000..3744d417562 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/public-api.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './resize-handle.component'; diff --git a/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html new file mode 100644 index 00000000000..72092e39325 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.html @@ -0,0 +1,23 @@ + + + + + diff --git a/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less new file mode 100644 index 00000000000..8eb1214ddb1 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.less @@ -0,0 +1,23 @@ +/* + * 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. + */ + +:host { + width: 24px; + height: 24px; + position: absolute; + right: 1px; + bottom: 1px; + color: #595959; + transition: opacity ease-out .2s; + cursor: se-resize; + z-index: 9; +} diff --git a/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts new file mode 100644 index 00000000000..b9d43322d33 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/resize-handle/resize-handle.component.ts @@ -0,0 +1,26 @@ +/* + * 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 { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'zeppelin-resize-handle', + templateUrl: './resize-handle.component.html', + styleUrls: ['./resize-handle.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush, + host: { + role: 'resize-handle' + } +}) +export class ResizeHandleComponent { + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts b/zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts new file mode 100644 index 00000000000..db6a7fc243a --- /dev/null +++ b/zeppelin-web-angular/src/app/share/run-scripts/run-scripts.directive.ts @@ -0,0 +1,80 @@ +/* + * 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 { Directive, ElementRef, Input, NgZone, OnChanges, Renderer2, SimpleChanges } from '@angular/core'; +import { SafeHtml } from '@angular/platform-browser'; +import { take } from 'rxjs/operators'; + +const loadedExternalScripts = new Set(); + +@Directive({ + selector: '[zeppelinRunScripts]' +}) +export class RunScriptsDirective implements OnChanges { + @Input() scriptsContent: string | SafeHtml; + + constructor(private elementRef: ElementRef, private ngZone: NgZone, private renderer: Renderer2) {} + + runScripts(): void { + if (!this.scriptsContent.toString()) { + return; + } + this.ngZone.onStable.pipe(take(1)).subscribe(() => { + this.ngZone.runOutsideAngular(() => { + const scripts = this.elementRef.nativeElement.getElementsByTagName('script'); + const externalScripts = []; + const localScripts = []; + for (let i = 0; i < scripts.length; i++) { + const script = scripts[i]; + if (script.text) { + localScripts.push(script); + } else if (script.src) { + externalScripts.push(script); + } + this.renderer.removeChild(this.elementRef.nativeElement, script); + } + Promise.all(externalScripts.map(s => this.loadExternalScript(s, this.elementRef.nativeElement))).then(() => { + localScripts.forEach(s => this.loadLocalScript(s, this.elementRef.nativeElement)); + }); + }); + }); + } + + loadExternalScript(script: HTMLScriptElement, parentNode: HTMLElement): Promise { + return new Promise(resolve => { + if (loadedExternalScripts.has(script.src)) { + resolve(); + } + const scriptCopy = this.renderer.createElement('script') as HTMLScriptElement; + scriptCopy.type = script.type ? script.type : 'text/javascript'; + scriptCopy.src = script.src; + scriptCopy.onload = () => { + resolve(); + loadedExternalScripts.add(script.src); + }; + parentNode.appendChild(scriptCopy); + }); + } + + loadLocalScript(script: HTMLScriptElement, parentNode: HTMLElement): void { + const scriptCopy = this.renderer.createElement('script') as HTMLScriptElement; + scriptCopy.type = script.type ? script.type : 'text/javascript'; + scriptCopy.text = `(function() { ${script.text} })();`; + parentNode.appendChild(scriptCopy); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.scriptsContent) { + this.runScripts(); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts new file mode 100644 index 00000000000..ed5d191736a --- /dev/null +++ b/zeppelin-web-angular/src/app/share/share.module.ts @@ -0,0 +1,100 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; + +import { + NzAlertModule, + NzBadgeModule, + NzButtonModule, + NzCardModule, + NzDividerModule, + NzDropDownModule, + NzFormModule, + NzGridModule, + NzIconModule, + NzInputModule, + NzMenuModule, + NzMessageModule, + NzModalModule, + NzNotificationModule, + NzPopconfirmModule, + NzProgressModule, + NzSelectModule, + NzTabsModule, + NzToolTipModule, + NzTreeModule, + NzUploadModule +} from 'ng-zorro-antd'; + +import { AboutZeppelinComponent } from '@zeppelin/share/about-zeppelin/about-zeppelin.component'; +import { CodeEditorModule } from '@zeppelin/share/code-editor'; +import { FolderRenameComponent } from '@zeppelin/share/folder-rename/folder-rename.component'; +import { HeaderComponent } from '@zeppelin/share/header/header.component'; +import { MathJaxDirective } from '@zeppelin/share/math-jax/math-jax.directive'; +import { NodeListComponent } from '@zeppelin/share/node-list/node-list.component'; +import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; +import { NoteImportComponent } from '@zeppelin/share/note-import/note-import.component'; +import { NoteRenameComponent } from '@zeppelin/share/note-rename/note-rename.component'; +import { PageHeaderComponent } from '@zeppelin/share/page-header/page-header.component'; +import { HumanizeBytesPipe } from '@zeppelin/share/pipes'; +import { RunScriptsDirective } from '@zeppelin/share/run-scripts/run-scripts.directive'; +import { SpinComponent } from '@zeppelin/share/spin/spin.component'; +import { ResizeHandleComponent } from './resize-handle'; + +const MODAL_LIST = [ + AboutZeppelinComponent, + NoteImportComponent, + NoteCreateComponent, + NoteRenameComponent, + FolderRenameComponent +]; +const EXPORT_LIST = [HeaderComponent, NodeListComponent, PageHeaderComponent, SpinComponent, ResizeHandleComponent]; +const PIPES = [HumanizeBytesPipe]; + +@NgModule({ + declarations: [MODAL_LIST, EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective], + entryComponents: [MODAL_LIST], + exports: [EXPORT_LIST, PIPES, MathJaxDirective, RunScriptsDirective, CodeEditorModule], + imports: [ + FormsModule, + CommonModule, + NzMenuModule, + NzIconModule, + NzInputModule, + NzDropDownModule, + NzBadgeModule, + NzGridModule, + NzModalModule, + NzTreeModule, + RouterModule, + NzButtonModule, + NzNotificationModule, + NzToolTipModule, + NzDividerModule, + NzMessageModule, + NzCardModule, + NzPopconfirmModule, + NzPopconfirmModule, + NzFormModule, + NzTabsModule, + NzUploadModule, + NzSelectModule, + NzAlertModule, + NzProgressModule, + CodeEditorModule + ] +}) +export class ShareModule {} diff --git a/zeppelin-web-angular/src/app/share/spin/spin.component.html b/zeppelin-web-angular/src/app/share/spin/spin.component.html new file mode 100644 index 00000000000..81b188308b1 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/spin/spin.component.html @@ -0,0 +1,21 @@ + + +
+
+ +
+

Zeppelin

+ +
+
+
diff --git a/zeppelin-web-angular/src/app/share/spin/spin.component.less b/zeppelin-web-angular/src/app/share/spin/spin.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/spin/spin.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/share/spin/spin.component.ts b/zeppelin-web-angular/src/app/share/spin/spin.component.ts new file mode 100644 index 00000000000..34e7cedd01a --- /dev/null +++ b/zeppelin-web-angular/src/app/share/spin/spin.component.ts @@ -0,0 +1,26 @@ +/* + * 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 { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'zeppelin-spin', + templateUrl: './spin.component.html', + styleUrls: ['./spin.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class SpinComponent implements OnInit { + @Input() transparent = false; + constructor() {} + + ngOnInit() {} +} diff --git a/zeppelin-web-angular/src/app/spell/spell-result.ts b/zeppelin-web-angular/src/app/spell/spell-result.ts new file mode 100644 index 00000000000..50051d2e94a --- /dev/null +++ b/zeppelin-web-angular/src/app/spell/spell-result.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +export class SpellResult { + static extractMagic(allParagraphText) { + const pattern = /^\s*%(\S+)\s*/g; + try { + const match = pattern.exec(allParagraphText); + if (match) { + return `%${match[1].trim()}`; + } + } catch (error) { + // failed to parse, ignore + } + + return undefined; + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html new file mode 100644 index 00000000000..4b4caf1d140 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.html @@ -0,0 +1,35 @@ + + +
+ + + + +
+
+ + View + + + + + + + + +
+
+
diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less new file mode 100644 index 00000000000..b8beb4c3cb5 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.less @@ -0,0 +1,15 @@ +/* + * 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. + */ + +.area-chart-setting { + margin: 10px 0; +} diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts new file mode 100644 index 00000000000..07ffb22cc4c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.component.ts @@ -0,0 +1,102 @@ +/* + * 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 { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; +import { setChartXAxis } from '../common/util/set-x-axis'; +import { VisualizationXAxisSettingComponent } from '../common/x-axis-setting/x-axis-setting.component'; + +@Component({ + selector: 'zeppelin-area-chart-visualization', + templateUrl: './area-chart-visualization.component.html', + styleUrls: ['./area-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AreaChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationXAxisSettingComponent, { static: false }) + xAxisSettingComponent: VisualizationXAxisSettingComponent; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + style: 'stream' | 'expand' | 'stack' = 'stack'; + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + viewChange() { + this.config.setting.stackedAreaChart.style = this.style; + this.visualization.configChange$.next(this.config); + } + + ngOnInit() {} + + refreshSetting() { + this.style = this.config.setting.stackedAreaChart.style; + this.pivotSettingComponent.init(); + this.xAxisSettingComponent.init(); + this.cdr.markForCheck(); + } + + ngAfterViewInit(): void { + this.render(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore() { + const key = this.getKey(); + this.setScale(); + if (this.style === 'stack') { + // area:stack + this.chart + .areaStack() + .position(`${key}*__value__`) + .color('__key__'); + } else if (this.style === 'stream') { + // area:stream + this.chart + .area() + .position(`${key}*__value__`) + .adjust(['stack', 'symmetric']) + .color('__key__'); + } else { + // area:percent + this.chart + .areaStack() + .position(`${key}*__percent__`) + .color('__key__'); + } + + setChartXAxis(this.visualization, 'stackedAreaChart', this.chart, key); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts new file mode 100644 index 00000000000..a7f1b481c69 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/area-chart/area-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { AreaChartVisualizationComponent } from './area-chart-visualization.component'; + +export class AreaChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + AreaChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html new file mode 100644 index 00000000000..eb798668215 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.html @@ -0,0 +1,34 @@ + + +
+ + + + +
+ + View + + + + + + + +
+
+
+
diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less new file mode 100644 index 00000000000..cd842d1ed23 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.less @@ -0,0 +1,25 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + bar-chart-setting { + margin: 10px 0; + } + .field-setting-wrap { + margin-top: 10px; + } + .drag-wrap { + min-height: 23px; + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts new file mode 100644 index 00000000000..82ed55f0dcf --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts @@ -0,0 +1,107 @@ +/* + * 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 { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { get } from 'lodash'; + +import { VisualizationMultiBarChart } from '@zeppelin/sdk'; +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; +import { setChartXAxis } from '../common/util/set-x-axis'; +import { VisualizationXAxisSettingComponent } from '../common/x-axis-setting/x-axis-setting.component'; + +@Component({ + selector: 'zeppelin-bar-chart-visualization', + templateUrl: './bar-chart-visualization.component.html', + styleUrls: ['./bar-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class BarChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationXAxisSettingComponent, { static: false }) + xAxisSettingComponent: VisualizationXAxisSettingComponent; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + stacked = false; + + viewChange() { + if (!this.config.setting.multiBarChart) { + this.config.setting.multiBarChart = new VisualizationMultiBarChart(); + } + this.config.setting.multiBarChart.stacked = this.stacked; + this.visualization.configChange$.next(this.config); + } + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + ngOnInit() {} + + ngAfterViewInit() { + this.render(); + } + + refreshSetting() { + this.stacked = get(this.config.setting, 'multiBarChart.stacked', false); + this.pivotSettingComponent.init(); + this.xAxisSettingComponent.init(); + this.cdr.markForCheck(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore(chart) { + const key = this.getKey(); + this.setScale(); + + if (get(this.config.setting, 'multiBarChart.stacked', false)) { + this.chart + .intervalStack() + .position(`${key}*__value__`) + .color('__key__') + .opacity(1); + } else { + this.chart + .interval() + .position(`${key}*__value__`) + .color('__key__') + .opacity(1) + .adjust([ + { + type: 'dodge', + marginRatio: 0 + } + ]); + } + setChartXAxis(this.visualization, 'multiBarChart', this.chart, key); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts new file mode 100644 index 00000000000..736e43dadd1 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.ts @@ -0,0 +1,31 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { BarChartVisualizationComponent } from './bar-chart-visualization.component'; + +export class BarChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + BarChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html new file mode 100644 index 00000000000..2a91d7beccd --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html @@ -0,0 +1,85 @@ + + + +
+ {{item.name}} +
+
+
+ +
+ + {{item.name}} + + +
+
+
+
+ +
+ + {{item.name}} + + +
+
+
+
+ +
+ + {{item.name}} {{item.aggr | uppercase}}  + + +
    +
  • + {{aggregate}} +
  • +
+
+
+
+
+
+
+
diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less new file mode 100644 index 00000000000..87bb382eaea --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.less @@ -0,0 +1,27 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + display: block; + margin: 10px 0; + .field-setting-wrap { + margin-top: 24px; + } + .drag-wrap { + min-height: 23px; + } + nz-card { + background: #fff; + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts new file mode 100644 index 00000000000..12abf17c79c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts @@ -0,0 +1,89 @@ +/* + * 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 { copyArrayItem, moveItemInArray, transferArrayItem, CdkDragDrop } from '@angular/cdk/drag-drop'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { TableData, Visualization } from '@zeppelin/visualization'; + +@Component({ + selector: 'zeppelin-visualization-pivot-setting', + templateUrl: './pivot-setting.component.html', + styleUrls: ['./pivot-setting.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class VisualizationPivotSettingComponent implements OnInit { + @Input() visualization: Visualization; + + tableData: TableData; + config: GraphConfig; + columns = []; + aggregates = ['sum', 'count', 'avg', 'min', 'max']; + + // tslint:disable-next-line + drop(event: CdkDragDrop) { + if (event.container.id === 'columns-list') { + return; + } + if (event.previousContainer === event.container) { + moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); + } else { + if ( + event.container.id !== 'value-list' && + event.container.data.findIndex(e => e.name === event.previousContainer.data[event.previousIndex].name) !== -1 + ) { + return; + } + if (event.previousContainer.id === 'columns-list') { + copyArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); + } else { + transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex); + } + } + this.visualization.configChange$.next(this.config); + } + + // tslint:disable-next-line + removeFieldAt(data: any[], index: number): void { + data.splice(index, 1); + this.visualization.configChange$.next(this.config); + this.cdr.markForCheck(); + } + + changeAggregate(aggregates: string, index: number): void { + this.config.values[index].aggr = aggregates; + this.visualization.configChange$.next(this.config); + this.cdr.markForCheck(); + } + + noReturnPredicate() { + return false; + } + + init() { + this.tableData = this.visualization.getTransformation().getTableData() as TableData; + this.config = this.visualization.getConfig(); + this.columns = this.tableData.columns.map((name, index) => ({ + name, + index, + aggr: 'sum' + })); + this.cdr.markForCheck(); + } + + constructor(private cdr: ChangeDetectorRef) {} + + ngOnInit() { + this.init(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html new file mode 100644 index 00000000000..ff03338c481 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.html @@ -0,0 +1,98 @@ + + + +
+ {{item.name}} +
+
+
+ +
+ + {{item.name}} + + +
+
+
+
+ +
+ + {{item.name}} + + +
+
+
+
+ +
+ + {{item.name}} + + +
+
+
+
+ +
+ + {{item.name}} + + +
+
+
+ +
+
diff --git a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less new file mode 100644 index 00000000000..01427854d96 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.less @@ -0,0 +1,27 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + display: block; + margin: 10px 0; + .field-setting-wrap { + margin-top: 10px; + } + .drag-wrap { + min-height: 23px; + } + nz-card { + background: #fff; + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts new file mode 100644 index 00000000000..e154549e43e --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/scatter-setting/scatter-setting.component.ts @@ -0,0 +1,102 @@ +/* + * 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 { CdkDragDrop } from '@angular/cdk/drag-drop'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { get } from 'lodash'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { TableData, Visualization } from '@zeppelin/visualization'; + +@Component({ + selector: 'zeppelin-visualization-scatter-setting', + templateUrl: './scatter-setting.component.html', + styleUrls: ['./scatter-setting.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class VisualizationScatterSettingComponent implements OnInit { + @Input() visualization: Visualization; + + tableData: TableData; + config: GraphConfig; + columns = []; + + field = { + xAxis: [], + yAxis: [], + group: [], + size: [] + }; + + // tslint:disable-next-line + drop(event: CdkDragDrop) { + this.clean(event.container.data, false); + event.container.data.push(event.previousContainer.data[event.previousIndex]); + this.cdr.markForCheck(); + this.updateConfig(); + } + + // tslint:disable-next-line + clean(data: any[], update = true): void { + while (data.length > 0) { + data.splice(0, 1); + } + if (update) { + this.updateConfig(); + } + this.cdr.markForCheck(); + } + + noReturnPredicate() { + return false; + } + + updateConfig() { + if (!this.config.setting.scatterChart) { + this.config.setting.scatterChart = {}; + } + const scatterSetting = this.config.setting.scatterChart; + scatterSetting.xAxis = this.field.xAxis[0]; + scatterSetting.yAxis = this.field.yAxis[0]; + scatterSetting.size = this.field.size[0]; + scatterSetting.group = this.field.group[0]; + this.visualization.configChange$.next(this.config); + } + + constructor(private cdr: ChangeDetectorRef) {} + + init() { + this.tableData = this.visualization.getTransformation().getTableData() as TableData; + this.config = this.visualization.getConfig(); + this.columns = this.tableData.columns.map((name, index) => ({ + name, + index, + aggr: 'sum' + })); + + const xAxis = get(this.config.setting, 'scatterChart.xAxis', this.columns[0]); + const yAxis = get(this.config.setting, 'scatterChart.yAxis', this.columns[1]); + const group = get(this.config.setting, 'scatterChart.group'); + const size = get(this.config.setting, 'scatterChart.size'); + const arrayWrapper = value => (value ? [value] : []); + this.field.xAxis = arrayWrapper(xAxis); + this.field.yAxis = arrayWrapper(yAxis); + this.field.group = arrayWrapper(group); + this.field.size = arrayWrapper(size); + this.cdr.markForCheck(); + } + + ngOnInit() { + this.init(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts b/zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts new file mode 100644 index 00000000000..bfa81a8df81 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/util/calc-tick-count.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +export const DEFAULT_TICK_COUNT = 16; + +export function calcTickCount(el: HTMLElement) { + if (el && el.getBoundingClientRect) { + const tickCount = Math.round(el.getBoundingClientRect().width / 60); + return Number.isNaN(tickCount) ? DEFAULT_TICK_COUNT : tickCount; + } else { + return DEFAULT_TICK_COUNT; + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts b/zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts new file mode 100644 index 00000000000..e41ad7983a0 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/util/set-x-axis.ts @@ -0,0 +1,46 @@ +/* + * 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 * as G2 from '@antv/g2'; +import { get } from 'lodash'; + +import { Visualization } from '@zeppelin/visualization'; + +export function setChartXAxis( + visualization: Visualization, + mode: 'lineChart' | 'multiBarChart' | 'stackedAreaChart', + chart: G2.Chart, + key: string +) { + const config = visualization.getConfig(); + const setting = config.setting[mode]; + chart.axis(key, { + label: { + textStyle: { + rotate: 0 + } + } + }); + switch (setting.xLabelStatus) { + case 'hide': + chart.axis(key, false); + break; + case 'rotate': + chart.axis(key, { + label: { + textStyle: { + rotate: Number.parseInt(get(setting, 'rotate.degree', '-45'), 10) + } + } + }); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html new file mode 100644 index 00000000000..cd11081ab04 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.html @@ -0,0 +1,38 @@ + + +
+ + xAxis + + + + + + + + + + degree + + + + + + + +
diff --git a/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less new file mode 100644 index 00000000000..3e7f1f963ba --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.less @@ -0,0 +1,18 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + display: block; + margin: 10px 0; +}); diff --git a/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts new file mode 100644 index 00000000000..0a5d5460de7 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/x-axis-setting/x-axis-setting.component.ts @@ -0,0 +1,78 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; + +import { get } from 'lodash'; + +import { GraphConfig, XAxisSetting, XLabelStatus } from '@zeppelin/sdk'; +import { Visualization } from '@zeppelin/visualization'; + +@Component({ + selector: 'zeppelin-visualization-x-axis-setting', + templateUrl: './x-axis-setting.component.html', + styleUrls: ['./x-axis-setting.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class VisualizationXAxisSettingComponent implements OnInit { + @Input() visualization: Visualization; + @Input() mode: 'lineChart' | 'multiBarChart' | 'stackedAreaChart'; + + setting: XAxisSetting; + config: GraphConfig; + xLabelStatus: XLabelStatus = 'default'; + degree = '-45'; + previousDegree: string; + constructor(private cdr: ChangeDetectorRef) {} + + onStatusChange() { + this.setting.xLabelStatus = this.xLabelStatus; + this.updateConfig(); + } + + onDegreeChange() { + if (this.degree === this.previousDegree) { + return; + } + const degree = Number.parseInt(this.degree, 10); + if (Number.isNaN(degree)) { + this.degree = this.previousDegree; + return; + } else { + this.degree = `${degree}`; + this.previousDegree = this.degree; + } + this.updateConfig(); + } + + updateConfig() { + this.setting.rotate.degree = this.degree; + this.setting.xLabelStatus = this.xLabelStatus; + this.visualization.configChange$.next(this.config); + } + + init() { + this.config = this.visualization.getConfig(); + this.setting = this.config.setting[this.mode]; + if (!this.setting.rotate) { + this.setting.rotate = { degree: '-45' }; + } + this.xLabelStatus = get(this.setting, ['xLabelStatus'], 'default'); + this.degree = get(this.setting, ['rotate', 'degree'], '-45'); + this.previousDegree = this.degree; + this.cdr.markForCheck(); + } + + ngOnInit() { + this.init(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html new file mode 100644 index 00000000000..cb8faab7ed4 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.html @@ -0,0 +1,44 @@ + + +
+ + +
+ +
+ +
+ +
+ + +
+
+
diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less new file mode 100644 index 00000000000..8e84bc5be30 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.less @@ -0,0 +1,25 @@ +/* + * 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 "theme-mixin"; + +.themeMixin({ + .zoom-tips { + color: @text-color-secondary; + } + .line-setting { + margin: 10px 0; + input.format-input { + width: 160px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts new file mode 100644 index 00000000000..02938e55327 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.component.ts @@ -0,0 +1,137 @@ +/* + * 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 { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; +import { setChartXAxis } from '../common/util/set-x-axis'; +import { VisualizationXAxisSettingComponent } from '../common/x-axis-setting/x-axis-setting.component'; + +@Component({ + selector: 'zeppelin-line-chart-visualization', + templateUrl: './line-chart-visualization.component.html', + styleUrls: ['./line-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class LineChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationXAxisSettingComponent, { static: false }) + xAxisSettingComponent: VisualizationXAxisSettingComponent; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + forceY = false; + lineWithFocus = false; + isDateFormat = false; + dateFormat = ''; + + settingChange(): void { + const setting = this.config.setting.lineChart; + setting.lineWithFocus = this.lineWithFocus; + setting.forceY = this.forceY; + setting.isDateFormat = this.isDateFormat; + setting.dateFormat = this.dateFormat; + this.visualization.configChange$.next(this.config); + } + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + ngOnInit() {} + + refreshSetting() { + const setting = this.config.setting.lineChart; + this.forceY = setting.forceY || false; + this.lineWithFocus = setting.lineWithFocus || false; + this.isDateFormat = setting.isDateFormat || false; + this.dateFormat = setting.dateFormat || ''; + this.pivotSettingComponent.init(); + this.xAxisSettingComponent.init(); + this.cdr.markForCheck(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore() { + const key = this.getKey(); + const setting = this.config.setting.lineChart; + this.setScale(); + this.chart + .line() + .position(`${key}*__value__`) + .color('__key__'); + setChartXAxis(this.visualization, 'lineChart', this.chart, key); + + if (setting.isDateFormat) { + if (this.visualization.transformed && this.visualization.transformed.rows) { + const invalid = this.visualization.transformed.rows.some(r => { + const isInvalidDate = Number.isNaN(new Date(r[key]).valueOf()); + if (isInvalidDate) { + console.warn(`${r[key]} is [Invalid Date]`); + } + return isInvalidDate; + }); + if (invalid) { + return; + } + this.chart.scale({ + [key]: { + type: 'time', + mask: setting.dateFormat || 'YYYY-MM-DD' + } + }); + } + } + + if (setting.forceY) { + this.chart.scale({ + __value__: { + min: 0 + } + }); + } + } + + renderAfter() { + const setting = this.config.setting.lineChart; + if (setting.lineWithFocus) { + // tslint:disable-next-line + (this.chart as any).interact('brush'); + } else { + // tslint:disable-next-line:no-any + (this.chart as any).clearInteraction(); + } + } + + ngAfterViewInit() { + this.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts new file mode 100644 index 00000000000..0be29c7676b --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/line-chart/line-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { LineChartVisualizationComponent } from './line-chart-visualization.component'; + +export class LineChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + LineChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html new file mode 100644 index 00000000000..5ddf300130b --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.html @@ -0,0 +1,19 @@ + + +
+ + +
+
+
diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts new file mode 100644 index 00000000000..0edebaa9d44 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.component.ts @@ -0,0 +1,73 @@ +/* + * 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 { + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationPivotSettingComponent } from '../common/pivot-setting/pivot-setting.component'; + +@Component({ + selector: 'zeppelin-pie-chart-visualization', + templateUrl: './pie-chart-visualization.component.html', + styleUrls: ['./pie-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class PieChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationPivotSettingComponent, { static: false }) + pivotSettingComponent: VisualizationPivotSettingComponent; + + constructor(@Inject(VISUALIZATION) public visualization: Visualization) { + super(visualization); + } + + ngOnInit() {} + + refreshSetting() { + this.pivotSettingComponent.init(); + } + + setScale() { + // Noop + } + + renderBefore() { + this.chart.tooltip({ + showTitle: false + }); + this.chart.coord('theta', { + radius: 0.75 + }); + this.chart + .intervalStack() + .position('__value__') + .color('__key__') + .style({ + lineWidth: 1, + stroke: '#fff' + }) + .tooltip('__key__*__value__', (name, value) => ({ name, value })); + } + + ngAfterViewInit() { + this.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts new file mode 100644 index 00000000000..d70572dda10 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/pie-chart/pie-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { PieChartVisualizationComponent } from './pie-chart-visualization.component'; + +export class PieChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + PieChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html new file mode 100644 index 00000000000..ea1e3792c2c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.html @@ -0,0 +1,19 @@ + + +
+ + +
+
+
diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less new file mode 100644 index 00000000000..019b5ca53b5 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.less @@ -0,0 +1,12 @@ +/* + * 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. + */ + diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts new file mode 100644 index 00000000000..f1b8ae5d8e4 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.component.ts @@ -0,0 +1,89 @@ +/* + * 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 { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + Inject, + OnInit, + ViewChild +} from '@angular/core'; + +import { get } from 'lodash'; + +import { G2VisualizationComponentBase, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +import { VisualizationScatterSettingComponent } from '../common/scatter-setting/scatter-setting.component'; +import { calcTickCount } from '../common/util/calc-tick-count'; + +@Component({ + selector: 'zeppelin-scatter-chart-visualization', + templateUrl: './scatter-chart-visualization.component.html', + styleUrls: ['./scatter-chart-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ScatterChartVisualizationComponent extends G2VisualizationComponentBase implements OnInit, AfterViewInit { + @ViewChild('container', { static: false }) container: ElementRef; + @ViewChild(VisualizationScatterSettingComponent, { static: false }) + scatterSettingComponent: VisualizationScatterSettingComponent; + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) { + super(visualization); + } + + refreshSetting() { + this.scatterSettingComponent.init(); + this.cdr.markForCheck(); + } + + setScale() { + const key = this.getKey(); + const tickCount = calcTickCount(this.container.nativeElement); + this.chart.scale(key, { + tickCount, + type: 'cat' + }); + } + + renderBefore() { + const key = this.getKey(); + const size = get(this.config.setting, 'scatterChart.size.name'); + this.setScale(); + this.chart.tooltip({ + crosshairs: { + type: 'cross' + } + }); + this.chart.legend('__value__', false); + // point + const geom = this.chart + .point() + .position(`${key}*__value__`) + .color('__key__') + // .adjust('jitter') + .opacity(0.65) + .shape('circle'); + + if (size) { + geom.size('__value__'); + } + } + + ngOnInit() {} + + ngAfterViewInit() { + this.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts new file mode 100644 index 00000000000..0bfafab328c --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/scatter-chart/scatter-chart-visualization.ts @@ -0,0 +1,32 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { G2VisualizationBase, VisualizationComponentPortal } from '@zeppelin/visualization'; + +import { ScatterChartVisualizationComponent } from './scatter-chart-visualization.component'; + +export class ScatterChartVisualization extends G2VisualizationBase { + componentPortal = new VisualizationComponentPortal( + this, + ScatterChartVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html new file mode 100644 index 00000000000..db43a53f0db --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html @@ -0,0 +1,123 @@ + + + + + + + + + + + {{col}} + + +
    + +
  • +
  • + Type +
      +
    • + {{type | titlecase}} +
    • +
    +
  • +
  • +
  • + Aggregation +
      +
    • + {{aggregation | titlecase}} +
    • +
    +
  • +
+
+ + + + + + {{data[col]}} + + +
+ +
+ + + {{aggregation}}({{col}}): {{colOptions.get(col).aggregationValue}} + + +
+
diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less new file mode 100644 index 00000000000..094ea9ac640 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.less @@ -0,0 +1,44 @@ +/* + * 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 "theme-mixin"; + +.th-dropdown { + .search-bar.ant-menu-item-group { + padding: 5px 12px; + ::ng-deep .ant-menu-item-group-title{ + display: none; + } + } +} + +.export-dropdown { + margin-bottom: 16px; + position: absolute; + bottom: 0; + left: 0; +} + +.themeMixin({ + display: block; + position: relative; + ::ng-deep .filter-icon svg { + transition: transform 300ms; + } + + .aggregation-wrap { + text-align: right; + .aggregation-item { + margin-left: 10px; + } + } +}); diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts new file mode 100644 index 00000000000..09fa0778426 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts @@ -0,0 +1,174 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, ViewChild } from '@angular/core'; + +import { filter, maxBy, minBy, orderBy, sumBy } from 'lodash'; +import { NzTableComponent } from 'ng-zorro-antd'; +import { utils, writeFile, WorkSheet } from 'xlsx'; + +import { TableData, Visualization, VISUALIZATION } from '@zeppelin/visualization'; + +type ColType = 'string' | 'date' | 'number'; +type AggregationType = 'count' | 'sum' | 'min' | 'max' | 'avg'; + +class FilterOption { + sort: 'desc' | 'asc' | '' = ''; + type: ColType = 'string'; + visible = true; + pinned?: string; + term = ''; + width: string | '*' = '*'; + aggregation: AggregationType | null = null; + aggregationValue: number | null = null; +} + +function typeCoercion(value: string, type: ColType): string | number | Date { + switch (type) { + case 'number': + const num = Number.parseFloat(value); + return Number.isNaN(num) ? value : num; + case 'date': + const date = new Date(value); + return Number.isNaN(date.valueOf()) ? value : date; + default: + return value; + } +} + +@Component({ + selector: 'zeppelin-visualization-table-visualization', + templateUrl: './table-visualization.component.html', + styleUrls: ['./table-visualization.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class TableVisualizationComponent implements OnInit { + tableData: TableData; + // tslint:disable-next-line:no-any + rows: any[] = []; + columns: string[] = []; + colOptions = new Map(); + types: ColType[] = ['string', 'number', 'date']; + aggregations: AggregationType[] = ['count', 'sum', 'min', 'max', 'avg']; + @ViewChild(NzTableComponent, { static: false }) nzTable: NzTableComponent; + + exportFile(type: 'csv' | 'xlsx', all = true) { + const wb = utils.book_new(); + let ws: WorkSheet; + if (all) { + ws = utils.json_to_sheet(this.rows); + } else { + ws = utils.json_to_sheet(this.nzTable.data); + } + utils.book_append_sheet(wb, ws, 'Sheet1'); + writeFile(wb, `export.${type}`); + } + + onChangeType(type: ColType, col: string) { + const opt = this.colOptions.get(col); + opt.type = type; + this.filterRows(); + this.aggregate(); + } + + onChangeAggregation(aggregation: AggregationType, col: string) { + const opt = this.colOptions.get(col); + opt.aggregation = opt.aggregation === aggregation ? null : aggregation; + this.aggregate(); + } + + onSearch(): void { + this.filterRows(); + } + + onSortChange(type: 'descend' | 'ascend' | string, key: string): void { + const opt: FilterOption = this.colOptions.get(key); + this.colOptions.delete(key); + if (type) { + opt.sort = type === 'descend' ? 'desc' : 'asc'; + } else { + opt.sort = ''; + } + this.colOptions.set(key, opt); + this.filterRows(); + } + + aggregate() { + this.colOptions.forEach((opt, key) => { + const numValue = row => { + const value = typeCoercion(row[key], opt.type); + if (typeof value === 'number') { + return value; + } + if (value instanceof Date) { + return value.valueOf(); + } + return value; + }; + const getSum = () => + sumBy(this.tableData.rows, row => { + const value = typeCoercion(row[key], 'number'); + return typeof value === 'number' ? value : 0; + }); + + switch (opt.aggregation) { + case 'sum': + opt.aggregationValue = getSum(); + break; + case 'avg': + opt.aggregationValue = getSum() / this.tableData.rows.length; + break; + case 'count': + opt.aggregationValue = this.tableData.rows.length; + break; + case 'max': + opt.aggregationValue = maxBy(this.tableData.rows, numValue)[key]; + break; + case 'min': + opt.aggregationValue = minBy(this.tableData.rows, numValue)[key]; + break; + default: + opt.aggregationValue = null; + } + }); + } + + filterRows() { + const sortKeys = []; + const sortTypes = []; + const terms = []; + this.colOptions.forEach((value, key) => { + if (value.sort) { + sortKeys.push(row => typeCoercion(row[key], value.type)); + sortTypes.push(value.sort); + } + terms.push(row => String(row[key]).search(value.term) !== -1); + }); + this.rows = filter(this.tableData.rows, row => terms.every(term => term(row))); + this.rows = orderBy(this.rows, sortKeys, sortTypes); + this.cdr.markForCheck(); + } + + constructor(@Inject(VISUALIZATION) public visualization: Visualization, private cdr: ChangeDetectorRef) {} + + ngOnInit() {} + + render() { + this.tableData = this.visualization.transformed; + this.columns = this.tableData.columns; + this.rows = [...this.tableData.rows]; + this.columns.forEach(col => { + this.colOptions.set(col, new FilterOption()); + }); + this.filterRows(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts new file mode 100644 index 00000000000..c2495b3157a --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.ts @@ -0,0 +1,60 @@ +/* + * 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 { CdkPortalOutlet } from '@angular/cdk/portal'; +import { ViewContainerRef } from '@angular/core'; + +import { GraphConfig } from '@zeppelin/sdk'; +import { + TableTransformation, + Transformation, + Visualization, + VisualizationComponentPortal +} from '@zeppelin/visualization'; + +import { TableVisualizationComponent } from './table-visualization.component'; + +export class TableVisualization extends Visualization { + tableTransformation = new TableTransformation(this.getConfig()); + componentPortal = new VisualizationComponentPortal( + this, + TableVisualizationComponent, + this.portalOutlet, + this.viewContainerRef + ); + constructor(config: GraphConfig, private portalOutlet: CdkPortalOutlet, private viewContainerRef: ViewContainerRef) { + super(config); + } + + destroy(): void { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + } + + getTransformation(): Transformation { + return this.tableTransformation; + } + + refresh(): void {} + + render(data): void { + this.transformed = data; + if (!this.componentRef) { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + this.componentRef.instance.render(); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/visualization.module.ts b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts new file mode 100644 index 00000000000..fe2f4a18cd4 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts @@ -0,0 +1,79 @@ +/* + * 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 { DragDropModule } from '@angular/cdk/drag-drop'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { + NzButtonModule, + NzCardModule, + NzCheckboxModule, + NzDropDownModule, + NzFormModule, + NzGridModule, + NzIconModule, + NzInputModule, + NzMenuModule, + NzRadioModule, + NzTableModule, + NzTagModule +} from 'ng-zorro-antd'; + +import { AreaChartVisualizationComponent } from './area-chart/area-chart-visualization.component'; +import { BarChartVisualizationComponent } from './bar-chart/bar-chart-visualization.component'; +import { VisualizationPivotSettingComponent } from './common/pivot-setting/pivot-setting.component'; +import { VisualizationScatterSettingComponent } from './common/scatter-setting/scatter-setting.component'; +import { VisualizationXAxisSettingComponent } from './common/x-axis-setting/x-axis-setting.component'; +import { LineChartVisualizationComponent } from './line-chart/line-chart-visualization.component'; +import { PieChartVisualizationComponent } from './pie-chart/pie-chart-visualization.component'; +import { ScatterChartVisualizationComponent } from './scatter-chart/scatter-chart-visualization.component'; +import { TableVisualizationComponent } from './table/table-visualization.component'; + +const VisualizationComponents = [ + TableVisualizationComponent, + AreaChartVisualizationComponent, + BarChartVisualizationComponent, + LineChartVisualizationComponent, + PieChartVisualizationComponent, + ScatterChartVisualizationComponent +]; + +@NgModule({ + declarations: [ + ...VisualizationComponents, + VisualizationPivotSettingComponent, + VisualizationScatterSettingComponent, + VisualizationXAxisSettingComponent + ], + entryComponents: [...VisualizationComponents], + exports: [...VisualizationComponents], + imports: [ + CommonModule, + FormsModule, + DragDropModule, + NzTableModule, + NzCardModule, + NzTagModule, + NzFormModule, + NzInputModule, + NzGridModule, + NzIconModule, + NzMenuModule, + NzDropDownModule, + NzRadioModule, + NzCheckboxModule, + NzButtonModule + ] +}) +export class VisualizationModule {} diff --git a/zeppelin-web-angular/src/assets/.gitkeep b/zeppelin-web-angular/src/assets/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/zeppelin-web-angular/src/assets/fonts/patua-one.woff2 b/zeppelin-web-angular/src/assets/fonts/patua-one.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..df2b38dc3025adb8fac45fad090522b6d62ea16a GIT binary patch literal 12844 zcmV+{GSkg>Pew8T0RR9105U894gdfE0C|`I05Q`50RR9100000000000000000000 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 K79##XA^-q%HNs>7 literal 0 HcmV?d00001 diff --git a/zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js b/zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js new file mode 100644 index 00000000000..23499a03dcd --- /dev/null +++ b/zeppelin-web-angular/src/assets/helium-packages/helium-vis-example.umd.js @@ -0,0 +1,589 @@ +/* + * 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. + */ + +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' + ? (module.exports = factory( + require('@zeppelin/helium'), + require('@angular/core'), + require('@zeppelin/visualization'), + require('@angular/common') + )) + : typeof define === 'function' && define.amd + ? define('helium-vis-example', [ + '@zeppelin/helium', + '@angular/core', + '@zeppelin/visualization', + '@angular/common' + ], factory) + : ((global = global || self), + (global['helium-vis-example'] = factory(global.helium, global.ng.core, global.visualization, global.ng.common))); +})(this, function(helium, core, visualization, common) { + 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + 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 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + /* global Reflect, Promise */ + + var extendStatics = function(d, b) { + extendStatics = + Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && + function(d, b) { + d.__proto__ = b; + }) || + function(d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + }; + return extendStatics(d, b); + }; + + function __extends(d, b) { + extendStatics(d, b); + function __() { + this.constructor = d; + } + d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __()); + } + + var __assign = function() { + __assign = + Object.assign || + function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; + + function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === 'function') + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; + } + return t; + } + + function __decorate(decorators, target, key, desc) { + var c = arguments.length, + r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc, + d; + if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function') + r = Reflect.decorate(decorators, target, key, desc); + else + for (var i = decorators.length - 1; i >= 0; i--) + if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; + } + + function __param(paramIndex, decorator) { + return function(target, key) { + decorator(target, key, paramIndex); + }; + } + + function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === 'object' && typeof Reflect.metadata === 'function') + return Reflect.metadata(metadataKey, metadataValue); + } + + function __awaiter(thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function(resolve, reject) { + function fulfilled(value) { + try { + step(generator.next(value)); + } catch (e) { + reject(e); + } + } + function rejected(value) { + try { + step(generator['throw'](value)); + } catch (e) { + reject(e); + } + } + function step(result) { + result.done + ? resolve(result.value) + : new P(function(resolve) { + resolve(result.value); + }).then(fulfilled, rejected); + } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); + } + + function __generator(thisArg, body) { + var _ = { + label: 0, + sent: function() { + if (t[0] & 1) throw t[1]; + return t[1]; + }, + trys: [], + ops: [] + }, + f, + y, + t, + g; + return ( + (g = { next: verb(0), throw: verb(1), return: verb(2) }), + typeof Symbol === 'function' && + (g[Symbol.iterator] = function() { + return this; + }), + g + ); + function verb(n) { + return function(v) { + return step([n, v]); + }; + } + function step(op) { + if (f) throw new TypeError('Generator is already executing.'); + while (_) + try { + if ( + ((f = 1), + y && + (t = op[0] & 2 ? y['return'] : op[0] ? y['throw'] || ((t = y['return']) && t.call(y), 0) : y.next) && + !(t = t.call(y, op[1])).done) + ) + return t; + if (((y = 0), t)) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: + case 1: + t = op; + break; + case 4: + _.label++; + return { value: op[1], done: false }; + case 5: + _.label++; + y = op[1]; + op = [0]; + continue; + case 7: + op = _.ops.pop(); + _.trys.pop(); + continue; + default: + if (!((t = _.trys), (t = t.length > 0 && t[t.length - 1])) && (op[0] === 6 || op[0] === 2)) { + _ = 0; + continue; + } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { + _.label = op[1]; + break; + } + if (op[0] === 6 && _.label < t[1]) { + _.label = t[1]; + t = op; + break; + } + if (t && _.label < t[2]) { + _.label = t[2]; + _.ops.push(op); + break; + } + if (t[2]) _.ops.pop(); + _.trys.pop(); + continue; + } + op = body.call(thisArg, _); + } catch (e) { + op = [6, e]; + y = 0; + } finally { + f = t = 0; + } + if (op[0] & 5) throw op[1]; + return { value: op[0] ? op[1] : void 0, done: true }; + } + } + + function __exportStar(m, exports) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; + } + + function __values(o) { + var m = typeof Symbol === 'function' && o[Symbol.iterator], + i = 0; + if (m) return m.call(o); + return { + next: function() { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + } + + function __read(o, n) { + var m = typeof Symbol === 'function' && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), + r, + ar = [], + e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } catch (error) { + e = { error: error }; + } finally { + try { + if (r && !r.done && (m = i['return'])) m.call(i); + } finally { + if (e) throw e.error; + } + } + return ar; + } + + function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); + return ar; + } + + function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; + return r; + } + + function __await(v) { + return this instanceof __await ? ((this.v = v), this) : new __await(v); + } + + function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError('Symbol.asyncIterator is not defined.'); + var g = generator.apply(thisArg, _arguments || []), + i, + q = []; + return ( + (i = {}), + verb('next'), + verb('throw'), + verb('return'), + (i[Symbol.asyncIterator] = function() { + return this; + }), + i + ); + function verb(n) { + if (g[n]) + i[n] = function(v) { + return new Promise(function(a, b) { + q.push([n, v, a, b]) > 1 || resume(n, v); + }); + }; + } + function resume(n, v) { + try { + step(g[n](v)); + } catch (e) { + settle(q[0][3], e); + } + } + function step(r) { + r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); + } + function fulfill(value) { + resume('next', value); + } + function reject(value) { + resume('throw', value); + } + function settle(f, v) { + if ((f(v), q.shift(), q.length)) resume(q[0][0], q[0][1]); + } + } + + function __asyncDelegator(o) { + var i, p; + return ( + (i = {}), + verb('next'), + verb('throw', function(e) { + throw e; + }), + verb('return'), + (i[Symbol.iterator] = function() { + return this; + }), + i + ); + function verb(n, f) { + i[n] = o[n] + ? function(v) { + return (p = !p) ? { value: __await(o[n](v)), done: n === 'return' } : f ? f(v) : v; + } + : f; + } + } + + function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError('Symbol.asyncIterator is not defined.'); + var m = o[Symbol.asyncIterator], + i; + return m + ? m.call(o) + : ((o = typeof __values === 'function' ? __values(o) : o[Symbol.iterator]()), + (i = {}), + verb('next'), + verb('throw'), + verb('return'), + (i[Symbol.asyncIterator] = function() { + return this; + }), + i); + function verb(n) { + i[n] = + o[n] && + function(v) { + return new Promise(function(resolve, reject) { + (v = o[n](v)), settle(resolve, reject, v.done, v.value); + }); + }; + } + function settle(resolve, reject, d, v) { + Promise.resolve(v).then(function(v) { + resolve({ value: v, done: d }); + }, reject); + } + } + + function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { + Object.defineProperty(cooked, 'raw', { value: raw }); + } else { + cooked.raw = raw; + } + return cooked; + } + + function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result.default = mod; + return result; + } + + function __importDefault(mod) { + return mod && mod.__esModule ? mod : { default: mod }; + } + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var JsonVisComponent = /** @class */ (function() { + function JsonVisComponent(visualization, cdr) { + this.visualization = visualization; + this.cdr = cdr; + } + /** + * @return {?} + */ + JsonVisComponent.prototype.ngOnInit = /** + * @return {?} + */ function() {}; + /** + * @return {?} + */ + JsonVisComponent.prototype.render = /** + * @return {?} + */ function() { + this.tableData = this.visualization.transformed; + }; + JsonVisComponent.decorators = [ + { + type: core.Component, + args: [ + { + selector: 'lib-helium-vis-example', + template: '\n
{{tableData | json}}
\n ', + changeDetection: core.ChangeDetectionStrategy.OnPush, + styles: [ + '\n pre {\n background: #fff7e7;\n padding: 10px;\n border: 1px solid #ffd278;\n color: #fa7e14;\n border-radius: 3px;\n }\n ' + ] + } + ] + } + ]; + /** @nocollapse */ + JsonVisComponent.ctorParameters = function() { + return [ + { type: visualization.Visualization, decorators: [{ type: core.Inject, args: [visualization.VISUALIZATION] }] }, + { type: core.ChangeDetectorRef } + ]; + }; + return JsonVisComponent; + })(); + if (false) { + /** @type {?} */ + JsonVisComponent.prototype.tableData; + /** @type {?} */ + JsonVisComponent.prototype.visualization; + /** + * @type {?} + * @private + */ + JsonVisComponent.prototype.cdr; + } + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var JsonVisModule = /** @class */ (function() { + function JsonVisModule() {} + JsonVisModule.decorators = [ + { + type: core.NgModule, + args: [ + { + imports: [common.CommonModule], + declarations: [JsonVisComponent], + entryComponents: [JsonVisComponent], + exports: [JsonVisComponent] + } + ] + } + ]; + return JsonVisModule; + })(); + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var JsonVisualization = /** @class */ (function(_super) { + __extends(JsonVisualization, _super); + function JsonVisualization(config, portalOutlet, viewContainerRef, componentFactoryResolver) { + var _this = _super.call(this, config) || this; + _this.portalOutlet = portalOutlet; + _this.viewContainerRef = viewContainerRef; + _this.componentFactoryResolver = componentFactoryResolver; + _this.tableTransformation = new visualization.TableTransformation(_this.getConfig()); + _this.componentPortal = new visualization.VisualizationComponentPortal( + _this, + JsonVisComponent, + _this.portalOutlet, + _this.viewContainerRef, + _this.componentFactoryResolver + ); + return _this; + } + /** + * @return {?} + */ + JsonVisualization.prototype.destroy = /** + * @return {?} + */ function() { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + this.configChange$.complete(); + this.configChange$ = null; + }; + /** + * @return {?} + */ + JsonVisualization.prototype.getTransformation = /** + * @return {?} + */ function() { + return this.tableTransformation; + }; + /** + * @return {?} + */ + JsonVisualization.prototype.refresh = /** + * @return {?} + */ function() {}; + /** + * @param {?} data + * @return {?} + */ + JsonVisualization.prototype.render = /** + * @param {?} data + * @return {?} + */ function(data) { + this.transformed = data; + if (!this.componentRef) { + this.componentRef = this.componentPortal.attachComponentPortal(); + } + this.componentRef.instance.render(); + }; + return JsonVisualization; + })(visualization.Visualization); + if (false) { + /** @type {?} */ + JsonVisualization.prototype.tableTransformation; + /** @type {?} */ + JsonVisualization.prototype.componentPortal; + /** + * @type {?} + * @private + */ + JsonVisualization.prototype.portalOutlet; + /** + * @type {?} + * @private + */ + JsonVisualization.prototype.viewContainerRef; + /** + * @type {?} + * @private + */ + JsonVisualization.prototype.componentFactoryResolver; + } + + /** + * @fileoverview added by tsickle + * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc + */ + var publicApi = helium.createHeliumPackage({ + name: 'helium-vis-example', + id: 'heliumVisExample', + icon: 'appstore', + type: helium.HeliumPackageType.Visualization, + module: JsonVisModule, + component: JsonVisComponent, + visualization: JsonVisualization + }); + + return publicApi; +}); +//# sourceMappingURL=helium-vis-example.umd.js.map diff --git a/zeppelin-web-angular/src/assets/images/bg.jpg b/zeppelin-web-angular/src/assets/images/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cffbba3ff89e5b7e68a247d7a3dc2c1b91c33001 GIT binary patch literal 185723 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 + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg b/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg new file mode 100644 index 00000000000..9e0b95d9197 --- /dev/null +++ b/zeppelin-web-angular/src/assets/images/zeppelin_svg_logo_bg.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/zeppelin-web-angular/src/browserslist b/zeppelin-web-angular/src/browserslist new file mode 100644 index 00000000000..37371cb04b9 --- /dev/null +++ b/zeppelin-web-angular/src/browserslist @@ -0,0 +1,11 @@ +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/zeppelin-web-angular/src/environments/environment.prod.ts b/zeppelin-web-angular/src/environments/environment.prod.ts new file mode 100644 index 00000000000..a00527f83a1 --- /dev/null +++ b/zeppelin-web-angular/src/environments/environment.prod.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export const environment = { + production: true +}; diff --git a/zeppelin-web-angular/src/environments/environment.ts b/zeppelin-web-angular/src/environments/environment.ts new file mode 100644 index 00000000000..7ed2ad9875b --- /dev/null +++ b/zeppelin-web-angular/src/environments/environment.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// This file can be replaced during build by using the `fileReplacements` array. +// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. +// The list of file replacements can be found in `angular.json`. + +export const environment = { + production: false +}; + +/* + * For easier debugging in development mode, you can import the following file + * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. + * + * This import should be commented out in production mode because it will have a negative impact + * on performance if an error is thrown. + */ +// import 'zone.js/dist/zone-error'; // Included with Angular CLI. diff --git a/zeppelin-web-angular/src/favicon.ico b/zeppelin-web-angular/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7e5049a11f67b8787f7a8cf012c4cf2fa90c325f GIT binary patch literal 4286 zcmb`LX^4$c7{|}J#iV8|AAIm-hz~-D6jOFmBvJN4$P%)KC=F#vWX}gme6VYTWGOQg zvZTnC&>&0J$vPNw{r)rWsnhYE_ud;u7=9X7!(xD5GWl{ybGE1`ppqi$dugmhiI=0)FmDtv&?a1r*xHE3t^ zhDu_(!fPmlu`mFv#&7C3;JstBKDT^?e+nD|t;1-T0Nq2nuAR76a1ZvtS#WcIrM((P z!fB`h*Kh0Ju+M9#KrqjNC|UIpT{4$nN_UD}+!@CSeYsE_uttLfK&;Mcxw4*LSJ>#%E2 zx_wX5&I^qIU%x0`{kA|=)OK^Yb$zE|mRtzTo@47P2{Q3?8;oOsRcBzWrBY!0`q z#=jQ&z(+4u=i-59)7-}HN9+ZlGiUR^qdpW)I5z9^%S*%z0o?(v?~B)#Z%V=(XinY! zT7zjY4>GOCV`An&=nUDs(umy$*tKSHW7eIf^XZSz=Cq~mvfW_Yp|VHZ9MG>D+=PcQ zIdn&LfsNpX=v zxczMX1a_U59gs8^Ha@QG7|_=ol!DHW);u%@?Z@>n9OBk1PSdr`j?g_a^A;En5=h(p#=OU;EO};kNY#-U8i8u02%0k)S`F9Eagt zluLWR9UP6?p`5wc-z4a3{&k1zy|uqTbSL)&%}Xxx92(QlkiP6_w2sOV)NKywE`VaV zf|2}R_|ZS>Dg$yF$d<>?uD)YVGR0hQRwE*wobnk zXx;zi`_If)FD?%4e6V*@uH!gE-`KY=PAg=K#-KYt7k#}aO+qR#sxYPzG>Ax1 orYiZb1PgtPsE(ngghb^L6_j+U6{$k38fr``oi1sRPL~(`0f&k}9RL6T literal 0 HcmV?d00001 diff --git a/zeppelin-web-angular/src/index.html b/zeppelin-web-angular/src/index.html new file mode 100644 index 00000000000..9ad5caa094f --- /dev/null +++ b/zeppelin-web-angular/src/index.html @@ -0,0 +1,50 @@ + + + + + + + + + Zeppelin + + + + +
+
+ +
+

Zeppelin

+ +
+
+
+
+ + + + diff --git a/zeppelin-web-angular/src/karma.conf.js b/zeppelin-web-angular/src/karma.conf.js new file mode 100644 index 00000000000..f2d0ea61a85 --- /dev/null +++ b/zeppelin-web-angular/src/karma.conf.js @@ -0,0 +1,43 @@ +/* + * 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. + */ + +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function(config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../coverage'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/zeppelin-web-angular/src/main.ts b/zeppelin-web-angular/src/main.ts new file mode 100644 index 00000000000..81b410d13ed --- /dev/null +++ b/zeppelin-web-angular/src/main.ts @@ -0,0 +1,25 @@ +/* + * 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 { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/zeppelin-web-angular/src/polyfills.ts b/zeppelin-web-angular/src/polyfills.ts new file mode 100644 index 00000000000..407a74e8552 --- /dev/null +++ b/zeppelin-web-angular/src/polyfills.ts @@ -0,0 +1,94 @@ +/* + * 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. + */ + +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE9, IE10 and IE11 requires all of the following polyfills. **/ +// import 'core-js/es6/symbol'; +// import 'core-js/es6/object'; +// import 'core-js/es6/function'; +// import 'core-js/es6/parse-int'; +// import 'core-js/es6/parse-float'; +// import 'core-js/es6/number'; +// import 'core-js/es6/math'; +// import 'core-js/es6/string'; +// import 'core-js/es6/date'; +// import 'core-js/es6/array'; +// import 'core-js/es6/regexp'; +// import 'core-js/es6/map'; +// import 'core-js/es6/weak-map'; +// import 'core-js/es6/set'; + +/** + * If the application will be indexed by Google Search, the following is required. + * Googlebot uses a renderer based on Chrome 41. + * https://developers.google.com/search/docs/guides/rendering + **/ +// import 'core-js/es6/array'; + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** IE10 and IE11 requires the following for the Reflect API. */ +// import 'core-js/es6/reflect'; + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + **/ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + */ + +// (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame +// (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick +// (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + +/* + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + */ +// (window as any).__Zone_enable_cross_context_check = true; + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +// tslint:disable +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ + +import 'core-js/es7/reflect'; diff --git a/zeppelin-web-angular/src/styles.less b/zeppelin-web-angular/src/styles.less new file mode 100644 index 00000000000..013b90e3af1 --- /dev/null +++ b/zeppelin-web-angular/src/styles.less @@ -0,0 +1,19 @@ +/* + * 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 './styles/spin'; +@import './styles/base'; +@import './styles/font'; +@import './styles/global'; +@import './styles/rewrite'; +@import "node_modules/ng-zorro-antd/resizable/style/entry.less"; +@import "node_modules/ng-zorro-antd/code-editor/style/entry.less"; diff --git a/zeppelin-web-angular/src/styles/base.less b/zeppelin-web-angular/src/styles/base.less new file mode 100644 index 00000000000..333ba34de73 --- /dev/null +++ b/zeppelin-web-angular/src/styles/base.less @@ -0,0 +1,18 @@ +/* + * 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. + */ + +* { + box-sizing: border-box; + outline: none; + margin: 0; + padding: 0; +} diff --git a/zeppelin-web-angular/src/styles/font.less b/zeppelin-web-angular/src/styles/font.less new file mode 100644 index 00000000000..ead6bcffa7e --- /dev/null +++ b/zeppelin-web-angular/src/styles/font.less @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/* latin */ +@font-face { + font-family: 'Patua One'; + font-style: normal; + font-weight: 400; + src: local('Patua One'), local('PatuaOne-Regular'), url(../assets/fonts/patua-one.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/zeppelin-web-angular/src/styles/global.less b/zeppelin-web-angular/src/styles/global.less new file mode 100644 index 00000000000..42e736228c1 --- /dev/null +++ b/zeppelin-web-angular/src/styles/global.less @@ -0,0 +1,124 @@ +/* + * 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 '../../node_modules/ng-zorro-antd/src/style/color/colors'; + +.mark-highlight { + color: crimson; +} + +.tips { + &.warning { + color: @volcano-6; + } + + &.error { + color: @red-6; + } +} + +.modal-footer { + padding: 10px 24px; + margin: 24px -24px -24px -24px; +} + +.transparent-button { + background: transparent; + border: none; + box-shadow: none; + + &:hover { + background: transparent; + } +} + +.padding-sm { + padding: 12px !important; +} + +.font-sm { + font-size: 12px; +} + +.opacity-05 { + opacity: 0.5; +} + +.drag-tag { + box-sizing: border-box; + color: rgba(0, 0, 0, 0.65); + font-variant: tabular-nums; + list-style: none; + font-feature-settings: 'tnum'; + display: inline-block; + height: auto; + margin: 0 8px 8px 0; + padding: 0 7px; + font-size: 12px; + line-height: 20px; + white-space: nowrap; + background: #fafafa; + border: 1px solid #d9d9d9; + border-radius: 0px; + cursor: pointer; + opacity: 1; + + &.cdk-drag-preview { + box-shadow: 0 0 6px -2px rgba(0, 0, 0, 0.2); + } + + &.cdk-drag-placeholder { + border-style: dashed; + } +} + +.interpreter-box { + margin-bottom: 12px; + line-height: 32px; + + &:last-child { + margin-bottom: 0; + } + + .refresh { + font-size: 18px; + line-height: 0; + margin-right: 12px; + } + + &.cdk-drag-placeholder { + opacity: 0; + } + + .interpreter-name { + display: inline-block; + + .main-name { + display: inline-block; + margin-right: 6px; + } + + .child-name { + font-size: 12px; + opacity: 0.7; + display: inline-block; + } + } +} + +//.view-lines { +// .view-line { +// &:first-child { +// filter: grayscale(1); +// } +// } +//} diff --git a/zeppelin-web-angular/src/styles/rewrite.less b/zeppelin-web-angular/src/styles/rewrite.less new file mode 100644 index 00000000000..43d7b61f32c --- /dev/null +++ b/zeppelin-web-angular/src/styles/rewrite.less @@ -0,0 +1,25 @@ +/* + * 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. + */ + +nz-tree { + .ant-tree { + nz-tree-node { + li { + padding: 0; + } + } + } +} + +.ant-tabs-nav .ant-tabs-tab { + font-weight: 500; +} diff --git a/zeppelin-web-angular/src/styles/spin.less b/zeppelin-web-angular/src/styles/spin.less new file mode 100644 index 00000000000..ec8c0a5a88c --- /dev/null +++ b/zeppelin-web-angular/src/styles/spin.less @@ -0,0 +1,150 @@ +/* + * 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. + */ + +.spin { + height: 100vh; + width: 100vw; + position: fixed; + z-index: 1000; + top: 0; + left: 0; + + &:after { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url("../assets/images/bg.jpg"); + background-size: cover; + filter: blur(4px); + background-repeat: no-repeat; + background-position: center; + } + + &.transparent { + &:after { + content: none; + } + } + + & > div { + background: rgba(255, 255, 255, 0.5); + text-align: center; + position: absolute; + z-index: 1; + top: 0; + bottom: 0; + left: 0; + right: 0; + + .logo { + width: 160px; + height: 160px; + margin: -64px auto 0; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + position: absolute; + + &:after { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + animation: opacity 2.0s infinite ease; + background-image: url(../assets/images/zeppelin_svg_logo.svg); + background-repeat: no-repeat; + background-position: center; + background-size: 75% auto; + } + } + + .spin-text { + width: 160px; + height: 160px; + top: 50%; + left: 50%; + transform: translateX(-50%); + position: absolute; + margin: -16px auto 0; + + .brand-title { + text-align: center; + font-family: 'Patua One', cursive; + color: #3071a9; + font-size: 40px; + display: block !important; + } + + .status { + margin: -6px auto 0; + width: 160px; + display: block !important; + color: #ffffff; + line-height: 24px; + height: 24px; + font-size: 12px; + position: relative; + background-color: rgba(48, 113, 169, 0.7); + + &::before { + content: ''; + position: absolute; + z-index: -1; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: #3071a9; + transform-origin: left center; + transform: scaleX(0); + transition: transform 0.2s ease-in-out; + animation: move 1.0s infinite ease; + } + } + } + } +} + +@keyframes opacity { + 0% { + opacity: 0.7; + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0.7; + } +} + + +@keyframes move { + 0% { + transform: scaleX(0); + transform-origin: left center; + } + 100% { + transform-origin: left center; + transform: scaleX(1); + } +} + + diff --git a/zeppelin-web-angular/src/styles/theme/dark/antd-dark.less b/zeppelin-web-angular/src/styles/theme/dark/antd-dark.less new file mode 100644 index 00000000000..16484d60a93 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/dark/antd-dark.less @@ -0,0 +1,17 @@ +/* + * 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. + */ + +html.dark { + @import '../../../../node_modules/ng-zorro-antd/ng-zorro-antd.less'; + @import 'theme-dark'; + @import '../markdown'; +} diff --git a/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less b/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less new file mode 100644 index 00000000000..26e91867283 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less @@ -0,0 +1,659 @@ +/* + * 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. + */ + +// The prefix to use on all css classes from ant. +@ant-prefix: ant; + +// An override for the html selector for theme prefixes +@html-selector: html; + +// -------- Colors ----------- +@primary-color: @blue-6; +@info-color: @blue-6; +@success-color: @green-6; +@processing-color: @blue-6; +@error-color: @red-6; +@highlight-color: @red-6; +@warning-color: @gold-6; +@normal-color: #d9d9d9; +@white: #fff; +@black: #000; + +// Color used by default to control hover and active backgrounds and for +// alert info backgrounds. +@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) +@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) +@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused +@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused +@primary-5: color( + ~`colorPalette('@{primary-color}', 5) ` +); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) +@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color +@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) +@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused +@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused +@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused + +// Base Scaffolding Variables +// --- + +// Background color for `` +@body-background: #fff; +// Base background color for most components +@component-background: #fff; +@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', + 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; +@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; +@text-color: fade(@black, 65%); +@text-color-secondary: fade(@black, 45%); +@text-color-warning: @gold-7; +@text-color-danger: @red-7; +@text-color-inverse: @white; +@icon-color: inherit; +@icon-color-hover: fade(@black, 75%); +@heading-color: fade(#000, 85%); +@heading-color-dark: fade(@white, 100%); +@text-color-dark: fade(@white, 85%); +@text-color-secondary-dark: fade(@white, 65%); +@font-variant-base: tabular-nums; +@font-feature-settings-base: 'tnum'; +@font-size-base: 14px; +@font-size-lg: @font-size-base + 2px; +@font-size-sm: 12px; +@heading-1-size: ceil(@font-size-base * 2.71); +@heading-2-size: ceil(@font-size-base * 2.14); +@heading-3-size: ceil(@font-size-base * 1.71); +@heading-4-size: ceil(@font-size-base * 1.42); +@line-height-base: 1.5; +@border-radius-base: 4px; +@border-radius-sm: 2px; + +// vertical paddings +@padding-lg: 24px; // containers +@padding-md: 16px; // small containers and buttons +@padding-sm: 12px; // Form controls and items +@padding-xs: 8px; // small items + +// vertical padding for all form controls +@control-padding-horizontal: @padding-sm; +@control-padding-horizontal-sm: @padding-xs; + +// The background colors for active and hover states for things like +// list items or table cells. +@item-active-bg: @primary-1; +@item-hover-bg: @primary-1; + +// ICONFONT +@iconfont-css-prefix: anticon; + +// LINK +@link-color: @primary-color; +@link-hover-color: color(~`colorPalette('@{link-color}', 5) `); +@link-active-color: color(~`colorPalette('@{link-color}', 7) `); +@link-decoration: none; +@link-hover-decoration: none; + +// Animation +@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); +@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); +@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); +@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); +@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); +@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); +@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); +@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); +@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); +@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); +@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); +@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); +@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); +@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); + +// Border color +@border-color-base: hsv(0, 0, 85%); // base border outline a component +@border-color-split: hsv(0, 0, 91%); // split border inside a component +@border-color-inverse: @white; +@border-width-base: 1px; // width of the border for a component +@border-style-base: solid; // style of a components border + +// Outline +@outline-blur-size: 0; +@outline-width: 2px; +@outline-color: @primary-color; + +@background-color-light: hsv(0, 0, 98%); // background of header and selected item +@background-color-base: hsv(0, 0, 96%); // Default grey background color + +// Disabled states +@disabled-color: fade(#000, 25%); +@disabled-bg: @background-color-base; +@disabled-color-dark: fade(#fff, 35%); + +// Shadow +@shadow-color: rgba(0, 0, 0, 0.15); +@shadow-color-inverse: @component-background; +@box-shadow-base: @shadow-1-down; +@shadow-1-up: 0 -2px 8px @shadow-color; +@shadow-1-down: 0 2px 8px @shadow-color; +@shadow-1-left: -2px 0 8px @shadow-color; +@shadow-1-right: 2px 0 8px @shadow-color; +@shadow-2: 0 4px 12px @shadow-color; + +// Buttons +@btn-font-weight: 400; +@btn-border-radius-base: @border-radius-base; +@btn-border-radius-sm: @border-radius-base; +@btn-border-width: @border-width-base; +@btn-border-style: @border-style-base; +@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); +@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); +@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); + +@btn-primary-color: #fff; +@btn-primary-bg: @primary-color; + +@btn-default-color: @text-color; +@btn-default-bg: #fff; +@btn-default-border: @border-color-base; + +@btn-danger-color: @error-color; +@btn-danger-bg: @background-color-base; +@btn-danger-border: @border-color-base; + +@btn-disable-color: @disabled-color; +@btn-disable-bg: @disabled-bg; +@btn-disable-border: @border-color-base; + +@btn-padding-base: 0 @padding-md - 1px; +@btn-font-size-lg: @font-size-lg; +@btn-font-size-sm: @font-size-base; +@btn-padding-lg: @btn-padding-base; +@btn-padding-sm: 0 @padding-xs - 1px; + +@btn-height-base: 32px; +@btn-height-lg: 40px; +@btn-height-sm: 24px; + +@btn-circle-size: @btn-height-base; +@btn-circle-size-lg: @btn-height-lg; +@btn-circle-size-sm: @btn-height-sm; + +@btn-square-size: @btn-height-base; +@btn-square-size-lg: @btn-height-lg; +@btn-square-size-sm: @btn-height-sm; + +@btn-group-border: @primary-5; + +// Checkbox +@checkbox-size: 16px; +@checkbox-color: @primary-color; +@checkbox-check-color: #fff; +@checkbox-border-width: @border-width-base; + +// Descriptions +@descriptions-bg: #fafafa; + +// Empty +@empty-font-size: @font-size-base; + +// Radio +@radio-size: 16px; +@radio-dot-color: @primary-color; + +// Radio buttons +@radio-button-bg: @btn-default-bg; +@radio-button-checked-bg: @btn-default-bg; +@radio-button-color: @btn-default-color; +@radio-button-hover-color: @primary-5; +@radio-button-active-color: @primary-7; + +// Media queries breakpoints +// Extra small screen / phone +@screen-xs: 480px; +@screen-xs-min: @screen-xs; + +// Small screen / tablet +@screen-sm: 576px; +@screen-sm-min: @screen-sm; + +// Medium screen / desktop +@screen-md: 768px; +@screen-md-min: @screen-md; + +// Large screen / wide desktop +@screen-lg: 992px; +@screen-lg-min: @screen-lg; + +// Extra large screen / full hd +@screen-xl: 1200px; +@screen-xl-min: @screen-xl; + +// Extra extra large screen / large desktop +@screen-xxl: 1600px; +@screen-xxl-min: @screen-xxl; + +// provide a maximum +@screen-xs-max: (@screen-sm-min - 1px); +@screen-sm-max: (@screen-md-min - 1px); +@screen-md-max: (@screen-lg-min - 1px); +@screen-lg-max: (@screen-xl-min - 1px); +@screen-xl-max: (@screen-xxl-min - 1px); + +// Grid system +@grid-columns: 24; +@grid-gutter-width: 0; + +// Layout +@layout-body-background: #f0f2f5; +@layout-header-background: #001529; +@layout-footer-background: @layout-body-background; +@layout-header-height: 64px; +@layout-header-padding: 0 50px; +@layout-footer-padding: 24px 50px; +@layout-sider-background: @layout-header-background; +@layout-trigger-height: 48px; +@layout-trigger-background: #002140; +@layout-trigger-color: #fff; +@layout-zero-trigger-width: 36px; +@layout-zero-trigger-height: 42px; +// Layout light theme +@layout-sider-background-light: #fff; +@layout-trigger-background-light: #fff; +@layout-trigger-color-light: @text-color; + +// z-index list, order by `z-index` +@zindex-table-fixed: auto; +@zindex-affix: 10; +@zindex-back-top: 10; +@zindex-badge: 10; +@zindex-picker-panel: 10; +@zindex-popup-close: 10; +@zindex-modal: 1000; +@zindex-modal-mask: 1000; +@zindex-message: 1010; +@zindex-notification: 1010; +@zindex-popover: 1030; +@zindex-dropdown: 1050; +@zindex-picker: 1050; +@zindex-tooltip: 1060; + +// Animation +@animation-duration-slow: 0.3s; // Modal +@animation-duration-base: 0.2s; +@animation-duration-fast: 0.1s; // Tooltip + +// Form +// --- +@label-required-color: @highlight-color; +@label-color: @heading-color; +@form-item-margin-bottom: 24px; +@form-item-trailing-colon: true; +@form-vertical-label-padding: 0 0 8px; +@form-vertical-label-margin: 0; + +// Input +// --- +@input-height-base: 32px; +@input-height-lg: 40px; +@input-height-sm: 24px; +@input-padding-horizontal: @control-padding-horizontal - 1px; +@input-padding-horizontal-base: @input-padding-horizontal; +@input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px; +@input-padding-horizontal-lg: @input-padding-horizontal; +@input-padding-vertical-base: 4px; +@input-padding-vertical-sm: 1px; +@input-padding-vertical-lg: 6px; +@input-placeholder-color: hsv(0, 0, 75%); +@input-color: @text-color; +@input-border-color: @border-color-base; +@input-bg: #fff; +@input-number-handler-active-bg: #f4f4f4; +@input-number-handler-hover-bg: @primary-5; +@input-number-handler-bg: @component-background; +@input-number-handler-border-color: @border-color-base; +@input-addon-bg: @background-color-light; +@input-hover-border-color: @primary-color; +@input-disabled-bg: @disabled-bg; +@input-outline-offset: 0 0; + +// Select +// --- +@select-border-color: @border-color-base; +@select-item-selected-font-weight: 600; +@select-dropdown-bg: @component-background; +@select-item-selected-bg: @background-color-light; +@select-item-active-bg: @item-active-bg; + +// Anchor +// --- +@anchor-border-color: @border-color-split; + +// Tooltip +// --- +// Tooltip max width +@tooltip-max-width: 250px; +// Tooltip text color +@tooltip-color: #fff; +// Tooltip background color +@tooltip-bg: rgba(0, 0, 0, 0.75); +// Tooltip arrow width +@tooltip-arrow-width: 5px; +// Tooltip distance with trigger +@tooltip-distance: @tooltip-arrow-width - 1px + 4px; +// Tooltip arrow color +@tooltip-arrow-color: @tooltip-bg; + +// Popover +// --- +// Popover body background color +@popover-bg: #fff; +// Popover text color +@popover-color: @text-color; +// Popover maximum width +@popover-min-width: 177px; +// Popover arrow width +@popover-arrow-width: 6px; +// Popover arrow color +@popover-arrow-color: @popover-bg; +// Popover outer arrow width +// Popover outer arrow color +@popover-arrow-outer-color: @popover-bg; +// Popover distance with trigger +@popover-distance: @popover-arrow-width + 4px; + +// Modal +// -- +@modal-body-padding: 24px; +@modal-header-bg: @component-background; +@modal-footer-bg: transparent; +@modal-footer-border-color-split: @border-color-split; +@modal-mask-bg: fade(@black, 45%); + +// Progress +// -- +@progress-default-color: @processing-color; +@progress-remaining-color: @background-color-base; +@progress-text-color: @text-color; + +// Menu +// --- +@menu-inline-toplevel-item-height: 40px; +@menu-item-height: 40px; +@menu-collapsed-width: 80px; +@menu-bg: @component-background; +@menu-popup-bg: @component-background; +@menu-item-color: @text-color; +@menu-highlight-color: @primary-color; +@menu-item-active-bg: @item-active-bg; +@menu-item-active-border-width: 3px; +@menu-item-group-title-color: @text-color-secondary; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; + +@menu-item-vertical-margin: 4px; +@menu-item-font-size: @font-size-base; +@menu-item-boundary-margin: 8px; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@dark-menu-item-hover-bg: transparent; + +// dark theme +@menu-dark-color: @text-color-secondary-dark; +@menu-dark-bg: @layout-header-background; +@menu-dark-arrow-color: #fff; +@menu-dark-submenu-bg: #000c17; +@menu-dark-highlight-color: #fff; +@menu-dark-item-active-bg: @primary-color; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@menu-dark-item-hover-bg: transparent; + +// Spin +// --- +@spin-dot-size-sm: 14px; +@spin-dot-size: 20px; +@spin-dot-size-lg: 32px; + +// Table +// -- +@table-header-bg: @background-color-light; +@table-header-color: @heading-color; +@table-header-sort-bg: @background-color-base; +@table-body-sort-bg: rgba(0, 0, 0, 0.01); +@table-row-hover-bg: @primary-1; +@table-selected-row-bg: #fafafa; +@table-expanded-row-bg: #fbfbfb; +@table-padding-vertical: 16px; +@table-padding-horizontal: 16px; +@table-border-radius-base: @border-radius-base; +@table-footer-bg: @background-color-light; +@table-footer-color: @heading-color; + +// Tag +// -- +@tag-default-bg: @background-color-light; +@tag-default-color: @text-color; +@tag-font-size: @font-size-sm; + +// TimePicker +// --- +@time-picker-panel-column-width: 56px; +@time-picker-panel-width: @time-picker-panel-column-width * 3; +@time-picker-selected-bg: @background-color-base; + +// Carousel +// --- +@carousel-dot-width: 16px; +@carousel-dot-height: 3px; +@carousel-dot-active-width: 24px; + +// Badge +// --- +@badge-height: 20px; +@badge-dot-size: 6px; +@badge-font-size: @font-size-sm; +@badge-font-weight: normal; +@badge-status-size: 6px; +@badge-text-color: @component-background; + +// Rate +// --- +@rate-star-color: @yellow-6; +@rate-star-bg: @border-color-split; + +// Card +// --- +@card-head-color: @heading-color; +@card-head-background: transparent; +@card-head-padding: 16px; +@card-inner-head-padding: 12px; +@card-padding-base: 24px; +@card-actions-background: @background-color-light; +@card-skeleton-bg: #cfd8dc; +@card-background: @component-background; +@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09); +@card-radius: @border-radius-sm; + +// Comment +// --- +@comment-padding-base: 16px 0; +@comment-nest-indent: 44px; +@comment-author-name-color: @text-color-secondary; +@comment-author-time-color: #ccc; +@comment-action-color: @text-color-secondary; +@comment-action-hover-color: #595959; + +// Tabs +// --- +@tabs-card-head-background: @background-color-light; +@tabs-card-height: 40px; +@tabs-card-active-color: @primary-color; +@tabs-title-font-size: @font-size-base; +@tabs-title-font-size-lg: @font-size-lg; +@tabs-title-font-size-sm: @font-size-base; +@tabs-ink-bar-color: @primary-color; +@tabs-bar-margin: 0 0 16px 0; +@tabs-horizontal-margin: 0 32px 0 0; +@tabs-horizontal-padding: 12px 16px; +@tabs-horizontal-padding-lg: 16px; +@tabs-horizontal-padding-sm: 8px 16px; +@tabs-vertical-padding: 8px 24px; +@tabs-vertical-margin: 0 0 16px 0; +@tabs-scrolling-size: 32px; +@tabs-highlight-color: @primary-color; +@tabs-hover-color: @primary-5; +@tabs-active-color: @primary-7; + +// BackTop +// --- +@back-top-color: #fff; +@back-top-bg: @text-color-secondary; +@back-top-hover-bg: @text-color; + +// Avatar +// --- +@avatar-size-base: 32px; +@avatar-size-lg: 40px; +@avatar-size-sm: 24px; +@avatar-font-size-base: 18px; +@avatar-font-size-lg: 24px; +@avatar-font-size-sm: 14px; +@avatar-bg: #ccc; +@avatar-color: #fff; +@avatar-border-radius: @border-radius-base; + +// Switch +// --- +@switch-height: 22px; +@switch-sm-height: 16px; +@switch-sm-checked-margin-left: -(@switch-sm-height - 3px); +@switch-disabled-opacity: 0.4; +@switch-color: @primary-color; +@switch-shadow-color: fade(#00230b, 20%); + +// Pagination +// --- +@pagination-item-size: 32px; +@pagination-item-size-sm: 24px; +@pagination-font-family: Arial; +@pagination-font-weight-active: 500; +@pagination-item-bg-active: transparent; + +// PageHeader +// --- +@page-header-padding: 24px; +@page-header-padding-vertical: 16px; @page-header-padding-vertical: 16px; +@page-header-padding-breadcrumb: 12px; +@page-header-back-color: #000; + +// Breadcrumb +// --- +@breadcrumb-base-color: @text-color-secondary; +@breadcrumb-last-item-color: @text-color; +@breadcrumb-font-size: @font-size-base; +@breadcrumb-icon-font-size: @font-size-base; +@breadcrumb-link-color: @text-color-secondary; +@breadcrumb-link-color-hover: @primary-5; +@breadcrumb-separator-color: @text-color-secondary; +@breadcrumb-separator-margin: 0 @padding-xs; + +// Slider +// --- +@slider-margin: 14px 6px 10px; +@slider-rail-background-color: @background-color-base; +@slider-rail-background-color-hover: #e1e1e1; +@slider-track-background-color: @primary-3; +@slider-track-background-color-hover: @primary-4; +@slider-handle-color: @primary-3; +@slider-handle-color-hover: @primary-4; +@slider-handle-color-focus: tint(@primary-color, 20%); +@slider-handle-color-focus-shadow: fade(@primary-color, 20%); +@slider-handle-color-tooltip-open: @primary-color; +@slider-dot-border-color: @border-color-split; +@slider-dot-border-color-active: tint(@primary-color, 50%); +@slider-disabled-color: @disabled-color; +@slider-disabled-background-color: @component-background; + +// Tree +// --- +@tree-title-height: 24px; +@tree-child-padding: 18px; +@tree-directory-selected-color: #fff; +@tree-directory-selected-bg: @primary-color; +@tree-node-hover-bg: @item-hover-bg; +@tree-node-selected-bg: @primary-2; + +// Collapse +// --- +@collapse-header-padding: 12px 16px 12px 40px; +@collapse-header-bg: @background-color-light; +@collapse-content-padding: @padding-md; +@collapse-content-bg: @component-background; + +// Skeleton +// --- +@skeleton-color: #f2f2f2; + +// Transfer +// --- +@transfer-disabled-bg: @disabled-bg; + +// Message +// --- +@message-notice-content-padding: 10px 16px; + +// Motion +// --- +@wave-animation-width: 6px; + +// Alert +// --- +@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; +@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; +@alert-success-icon-color: @success-color; +@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; +@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; +@alert-info-icon-color: @info-color; +@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; +@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; +@alert-warning-icon-color: @warning-color; +@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; +@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; +@alert-error-icon-color: @error-color; + +// List +// --- +@list-header-background: transparent; +@list-footer-background: transparent; +@list-empty-text-padding: @padding-md; +@list-item-padding: @padding-sm 0; +@list-item-meta-margin-bottom: @padding-md; +@list-item-meta-avatar-margin-right: @padding-md; +@list-item-meta-title-margin-bottom: @padding-sm; + +// Statistic +// --- +@statistic-title-font-size: @font-size-base; +@statistic-content-font-size: 24px; +@statistic-unit-font-size: 16px; +@statistic-font-family: @font-family; + +// Drawer +// --- +@drawer-header-padding: 16px 24px; +@drawer-body-padding: 24px; + +// Typography +// --- +@typography-title-font-weight: 600; diff --git a/zeppelin-web-angular/src/styles/theme/light/antd-light.less b/zeppelin-web-angular/src/styles/theme/light/antd-light.less new file mode 100644 index 00000000000..cb114e64f28 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/light/antd-light.less @@ -0,0 +1,15 @@ +/* + * 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 '../../../../node_modules/ng-zorro-antd/ng-zorro-antd.less'; +@import 'theme-light'; +@import '../markdown'; diff --git a/zeppelin-web-angular/src/styles/theme/light/theme-light.less b/zeppelin-web-angular/src/styles/theme/light/theme-light.less new file mode 100644 index 00000000000..6f071e5f728 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/light/theme-light.less @@ -0,0 +1,659 @@ +/* + * 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. + */ + +// The prefix to use on all css classes from ant. +@ant-prefix: ant; + +// An override for the html selector for theme prefixes +@html-selector: html; + +// -------- Colors ----------- +@primary-color: #3071a9; +@info-color: @blue-6; +@success-color: @green-6; +@processing-color: @blue-6; +@error-color: @red-6; +@highlight-color: @red-6; +@warning-color: @gold-6; +@normal-color: #d9d9d9; +@white: #fff; +@black: #000; + +// Color used by default to control hover and active backgrounds and for +// alert info backgrounds. +@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) +@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) +@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused +@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused +@primary-5: color( + ~`colorPalette('@{primary-color}', 5) ` +); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) +@primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color +@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) +@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused +@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused +@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused + +// Base Scaffolding Variables +// --- + +// Background color for `` +@body-background: #fff; +// Base background color for most components +@component-background: #fff; +@font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', + 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; +@code-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, Courier, monospace; +@text-color: fade(@black, 65%); +@text-color-secondary: fade(@black, 45%); +@text-color-warning: @gold-7; +@text-color-danger: @red-7; +@text-color-inverse: @white; +@icon-color: inherit; +@icon-color-hover: fade(@black, 75%); +@heading-color: fade(#000, 85%); +@heading-color-dark: fade(@white, 100%); +@text-color-dark: fade(@white, 85%); +@text-color-secondary-dark: fade(@white, 65%); +@font-variant-base: tabular-nums; +@font-feature-settings-base: 'tnum'; +@font-size-base: 14px; +@font-size-lg: @font-size-base + 2px; +@font-size-sm: 12px; +@heading-1-size: ceil(@font-size-base * 2.71); +@heading-2-size: ceil(@font-size-base * 2.14); +@heading-3-size: ceil(@font-size-base * 1.71); +@heading-4-size: ceil(@font-size-base * 1.42); +@line-height-base: 1.5; +@border-radius-base: 0px; +@border-radius-sm: 0px; + +// vertical paddings +@padding-lg: 24px; // containers +@padding-md: 16px; // small containers and buttons +@padding-sm: 12px; // Form controls and items +@padding-xs: 8px; // small items + +// vertical padding for all form controls +@control-padding-horizontal: @padding-sm; +@control-padding-horizontal-sm: @padding-xs; + +// The background colors for active and hover states for things like +// list items or table cells. +@item-active-bg: @primary-1; +@item-hover-bg: @primary-1; + +// ICONFONT +@iconfont-css-prefix: anticon; + +// LINK +@link-color: @primary-color; +@link-hover-color: color(~`colorPalette('@{link-color}', 5) `); +@link-active-color: color(~`colorPalette('@{link-color}', 7) `); +@link-decoration: none; +@link-hover-decoration: none; + +// Animation +@ease-base-out: cubic-bezier(0.7, 0.3, 0.1, 1); +@ease-base-in: cubic-bezier(0.9, 0, 0.3, 0.7); +@ease-out: cubic-bezier(0.215, 0.61, 0.355, 1); +@ease-in: cubic-bezier(0.55, 0.055, 0.675, 0.19); +@ease-in-out: cubic-bezier(0.645, 0.045, 0.355, 1); +@ease-out-back: cubic-bezier(0.12, 0.4, 0.29, 1.46); +@ease-in-back: cubic-bezier(0.71, -0.46, 0.88, 0.6); +@ease-in-out-back: cubic-bezier(0.71, -0.46, 0.29, 1.46); +@ease-out-circ: cubic-bezier(0.08, 0.82, 0.17, 1); +@ease-in-circ: cubic-bezier(0.6, 0.04, 0.98, 0.34); +@ease-in-out-circ: cubic-bezier(0.78, 0.14, 0.15, 0.86); +@ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1); +@ease-in-quint: cubic-bezier(0.755, 0.05, 0.855, 0.06); +@ease-in-out-quint: cubic-bezier(0.86, 0, 0.07, 1); + +// Border color +@border-color-base: hsv(0, 0, 85%); // base border outline a component +@border-color-split: hsv(0, 0, 91%); // split border inside a component +@border-color-inverse: @white; +@border-width-base: 1px; // width of the border for a component +@border-style-base: solid; // style of a components border + +// Outline +@outline-blur-size: 0; +@outline-width: 2px; +@outline-color: @primary-color; + +@background-color-light: hsv(0, 0, 98%); // background of header and selected item +@background-color-base: hsv(0, 0, 96%); // Default grey background color + +// Disabled states +@disabled-color: fade(#000, 25%); +@disabled-bg: @background-color-base; +@disabled-color-dark: fade(#fff, 35%); + +// Shadow +@shadow-color: rgba(0, 0, 0, 0.15); +@shadow-color-inverse: @component-background; +@box-shadow-base: @shadow-1-down; +@shadow-1-up: 0 -2px 8px @shadow-color; +@shadow-1-down: 0 2px 8px @shadow-color; +@shadow-1-left: -2px 0 8px @shadow-color; +@shadow-1-right: 2px 0 8px @shadow-color; +@shadow-2: 0 4px 12px @shadow-color; + +// Buttons +@btn-font-weight: 400; +@btn-border-radius-base: @border-radius-base; +@btn-border-radius-sm: @border-radius-base; +@btn-border-width: @border-width-base; +@btn-border-style: @border-style-base; +@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015); +@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045); +@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12); + +@btn-primary-color: #fff; +@btn-primary-bg: @primary-color; + +@btn-default-color: @text-color; +@btn-default-bg: #fff; +@btn-default-border: @border-color-base; + +@btn-danger-color: @error-color; +@btn-danger-bg: @background-color-base; +@btn-danger-border: @border-color-base; + +@btn-disable-color: @disabled-color; +@btn-disable-bg: @disabled-bg; +@btn-disable-border: @border-color-base; + +@btn-padding-base: 0 @padding-md - 1px; +@btn-font-size-lg: @font-size-lg; +@btn-font-size-sm: @font-size-base; +@btn-padding-lg: @btn-padding-base; +@btn-padding-sm: 0 @padding-xs - 1px; + +@btn-height-base: 32px; +@btn-height-lg: 40px; +@btn-height-sm: 24px; + +@btn-circle-size: @btn-height-base; +@btn-circle-size-lg: @btn-height-lg; +@btn-circle-size-sm: @btn-height-sm; + +@btn-square-size: @btn-height-base; +@btn-square-size-lg: @btn-height-lg; +@btn-square-size-sm: @btn-height-sm; + +@btn-group-border: @primary-5; + +// Checkbox +@checkbox-size: 16px; +@checkbox-color: @primary-color; +@checkbox-check-color: #fff; +@checkbox-border-width: @border-width-base; + +// Descriptions +@descriptions-bg: #fafafa; + +// Empty +@empty-font-size: @font-size-base; + +// Radio +@radio-size: 16px; +@radio-dot-color: @primary-color; + +// Radio buttons +@radio-button-bg: @btn-default-bg; +@radio-button-checked-bg: @btn-default-bg; +@radio-button-color: @btn-default-color; +@radio-button-hover-color: @primary-5; +@radio-button-active-color: @primary-7; + +// Media queries breakpoints +// Extra small screen / phone +@screen-xs: 480px; +@screen-xs-min: @screen-xs; + +// Small screen / tablet +@screen-sm: 576px; +@screen-sm-min: @screen-sm; + +// Medium screen / desktop +@screen-md: 768px; +@screen-md-min: @screen-md; + +// Large screen / wide desktop +@screen-lg: 992px; +@screen-lg-min: @screen-lg; + +// Extra large screen / full hd +@screen-xl: 1200px; +@screen-xl-min: @screen-xl; + +// Extra extra large screen / large desktop +@screen-xxl: 1600px; +@screen-xxl-min: @screen-xxl; + +// provide a maximum +@screen-xs-max: (@screen-sm-min - 1px); +@screen-sm-max: (@screen-md-min - 1px); +@screen-md-max: (@screen-lg-min - 1px); +@screen-lg-max: (@screen-xl-min - 1px); +@screen-xl-max: (@screen-xxl-min - 1px); + +// Grid system +@grid-columns: 24; +@grid-gutter-width: 0; + +// Layout +@layout-body-background: #f0f2f5; +@layout-header-background: #001529; +@layout-footer-background: @layout-body-background; +@layout-header-height: 64px; +@layout-header-padding: 0 50px; +@layout-footer-padding: 24px 50px; +@layout-sider-background: @layout-header-background; +@layout-trigger-height: 48px; +@layout-trigger-background: #002140; +@layout-trigger-color: #fff; +@layout-zero-trigger-width: 36px; +@layout-zero-trigger-height: 42px; +// Layout light theme +@layout-sider-background-light: #fff; +@layout-trigger-background-light: #fff; +@layout-trigger-color-light: @text-color; + +// z-index list, order by `z-index` +@zindex-table-fixed: auto; +@zindex-affix: 10; +@zindex-back-top: 10; +@zindex-badge: 10; +@zindex-picker-panel: 10; +@zindex-popup-close: 10; +@zindex-modal: 1000; +@zindex-modal-mask: 1000; +@zindex-message: 1010; +@zindex-notification: 1010; +@zindex-popover: 1030; +@zindex-dropdown: 1050; +@zindex-picker: 1050; +@zindex-tooltip: 1060; + +// Animation +@animation-duration-slow: 0.3s; // Modal +@animation-duration-base: 0.2s; +@animation-duration-fast: 0.1s; // Tooltip + +// Form +// --- +@label-required-color: @highlight-color; +@label-color: @heading-color; +@form-item-margin-bottom: 24px; +@form-item-trailing-colon: true; +@form-vertical-label-padding: 0 0 8px; +@form-vertical-label-margin: 0; + +// Input +// --- +@input-height-base: 32px; +@input-height-lg: 40px; +@input-height-sm: 24px; +@input-padding-horizontal: @control-padding-horizontal - 1px; +@input-padding-horizontal-base: @input-padding-horizontal; +@input-padding-horizontal-sm: @control-padding-horizontal-sm - 1px; +@input-padding-horizontal-lg: @input-padding-horizontal; +@input-padding-vertical-base: 4px; +@input-padding-vertical-sm: 1px; +@input-padding-vertical-lg: 6px; +@input-placeholder-color: hsv(0, 0, 75%); +@input-color: @text-color; +@input-border-color: @border-color-base; +@input-bg: #fff; +@input-number-handler-active-bg: #f4f4f4; +@input-number-handler-hover-bg: @primary-5; +@input-number-handler-bg: @component-background; +@input-number-handler-border-color: @border-color-base; +@input-addon-bg: @background-color-light; +@input-hover-border-color: @primary-color; +@input-disabled-bg: @disabled-bg; +@input-outline-offset: 0 0; + +// Select +// --- +@select-border-color: @border-color-base; +@select-item-selected-font-weight: 600; +@select-dropdown-bg: @component-background; +@select-item-selected-bg: @background-color-light; +@select-item-active-bg: @item-active-bg; + +// Anchor +// --- +@anchor-border-color: @border-color-split; + +// Tooltip +// --- +// Tooltip max width +@tooltip-max-width: 250px; +// Tooltip text color +@tooltip-color: #fff; +// Tooltip background color +@tooltip-bg: rgba(0, 0, 0, 0.75); +// Tooltip arrow width +@tooltip-arrow-width: 5px; +// Tooltip distance with trigger +@tooltip-distance: @tooltip-arrow-width - 1px + 4px; +// Tooltip arrow color +@tooltip-arrow-color: @tooltip-bg; + +// Popover +// --- +// Popover body background color +@popover-bg: #fff; +// Popover text color +@popover-color: @text-color; +// Popover maximum width +@popover-min-width: 177px; +// Popover arrow width +@popover-arrow-width: 6px; +// Popover arrow color +@popover-arrow-color: @popover-bg; +// Popover outer arrow width +// Popover outer arrow color +@popover-arrow-outer-color: @popover-bg; +// Popover distance with trigger +@popover-distance: @popover-arrow-width + 4px; + +// Modal +// -- +@modal-body-padding: 24px; +@modal-header-bg: @component-background; +@modal-footer-bg: transparent; +@modal-footer-border-color-split: @border-color-split; +@modal-mask-bg: fade(@black, 45%); + +// Progress +// -- +@progress-default-color: @processing-color; +@progress-remaining-color: @background-color-base; +@progress-text-color: @text-color; + +// Menu +// --- +@menu-inline-toplevel-item-height: 40px; +@menu-item-height: 40px; +@menu-collapsed-width: 80px; +@menu-bg: @component-background; +@menu-popup-bg: @component-background; +@menu-item-color: @text-color; +@menu-highlight-color: @primary-color; +@menu-item-active-bg: @item-active-bg; +@menu-item-active-border-width: 3px; +@menu-item-group-title-color: @text-color-secondary; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; + +@menu-item-vertical-margin: 4px; +@menu-item-font-size: @font-size-base; +@menu-item-boundary-margin: 8px; +@menu-icon-size: @font-size-base; +@menu-icon-size-lg: @font-size-lg; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@dark-menu-item-hover-bg: transparent; + +// dark theme +@menu-dark-color: @text-color-secondary-dark; +@menu-dark-bg: @layout-header-background; +@menu-dark-arrow-color: #fff; +@menu-dark-submenu-bg: #000c17; +@menu-dark-highlight-color: #fff; +@menu-dark-item-active-bg: @primary-color; +@menu-dark-selected-item-icon-color: @white; +@menu-dark-selected-item-text-color: @white; +@menu-dark-item-hover-bg: transparent; + +// Spin +// --- +@spin-dot-size-sm: 14px; +@spin-dot-size: 20px; +@spin-dot-size-lg: 32px; + +// Table +// -- +@table-header-bg: @background-color-light; +@table-header-color: @heading-color; +@table-header-sort-bg: @background-color-base; +@table-body-sort-bg: rgba(0, 0, 0, 0.01); +@table-row-hover-bg: @primary-1; +@table-selected-row-bg: #fafafa; +@table-expanded-row-bg: #fbfbfb; +@table-padding-vertical: 16px; +@table-padding-horizontal: 16px; +@table-border-radius-base: @border-radius-base; +@table-footer-bg: @background-color-light; +@table-footer-color: @heading-color; + +// Tag +// -- +@tag-default-bg: @background-color-light; +@tag-default-color: @text-color; +@tag-font-size: @font-size-sm; + +// TimePicker +// --- +@time-picker-panel-column-width: 56px; +@time-picker-panel-width: @time-picker-panel-column-width * 3; +@time-picker-selected-bg: @background-color-base; + +// Carousel +// --- +@carousel-dot-width: 16px; +@carousel-dot-height: 3px; +@carousel-dot-active-width: 24px; + +// Badge +// --- +@badge-height: 20px; +@badge-dot-size: 6px; +@badge-font-size: @font-size-sm; +@badge-font-weight: normal; +@badge-status-size: 6px; +@badge-text-color: @component-background; + +// Rate +// --- +@rate-star-color: @yellow-6; +@rate-star-bg: @border-color-split; + +// Card +// --- +@card-head-color: @heading-color; +@card-head-background: transparent; +@card-head-padding: 16px; +@card-inner-head-padding: 12px; +@card-padding-base: 24px; +@card-actions-background: @background-color-light; +@card-skeleton-bg: #cfd8dc; +@card-background: @component-background; +@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09); +@card-radius: @border-radius-sm; + +// Comment +// --- +@comment-padding-base: 16px 0; +@comment-nest-indent: 44px; +@comment-author-name-color: @text-color-secondary; +@comment-author-time-color: #ccc; +@comment-action-color: @text-color-secondary; +@comment-action-hover-color: #595959; + +// Tabs +// --- +@tabs-card-head-background: @background-color-light; +@tabs-card-height: 40px; +@tabs-card-active-color: @primary-color; +@tabs-title-font-size: @font-size-base; +@tabs-title-font-size-lg: @font-size-lg; +@tabs-title-font-size-sm: @font-size-base; +@tabs-ink-bar-color: @primary-color; +@tabs-bar-margin: 0 0 16px 0; +@tabs-horizontal-margin: 0 32px 0 0; +@tabs-horizontal-padding: 12px 16px; +@tabs-horizontal-padding-lg: 16px; +@tabs-horizontal-padding-sm: 8px 16px; +@tabs-vertical-padding: 8px 24px; +@tabs-vertical-margin: 0 0 16px 0; +@tabs-scrolling-size: 32px; +@tabs-highlight-color: @primary-color; +@tabs-hover-color: @primary-5; +@tabs-active-color: @primary-7; + +// BackTop +// --- +@back-top-color: #fff; +@back-top-bg: @text-color-secondary; +@back-top-hover-bg: @text-color; + +// Avatar +// --- +@avatar-size-base: 32px; +@avatar-size-lg: 40px; +@avatar-size-sm: 24px; +@avatar-font-size-base: 18px; +@avatar-font-size-lg: 24px; +@avatar-font-size-sm: 14px; +@avatar-bg: #ccc; +@avatar-color: #fff; +@avatar-border-radius: @border-radius-base; + +// Switch +// --- +@switch-height: 22px; +@switch-sm-height: 16px; +@switch-sm-checked-margin-left: -(@switch-sm-height - 3px); +@switch-disabled-opacity: 0.4; +@switch-color: @primary-color; +@switch-shadow-color: fade(#00230b, 20%); + +// Pagination +// --- +@pagination-item-size: 32px; +@pagination-item-size-sm: 24px; +@pagination-font-family: Arial; +@pagination-font-weight-active: 500; +@pagination-item-bg-active: transparent; + +// PageHeader +// --- +@page-header-padding: 24px; +@page-header-padding-vertical: 16px; @page-header-padding-vertical: 16px; +@page-header-padding-breadcrumb: 12px; +@page-header-back-color: #000; + +// Breadcrumb +// --- +@breadcrumb-base-color: @text-color-secondary; +@breadcrumb-last-item-color: @text-color; +@breadcrumb-font-size: @font-size-base; +@breadcrumb-icon-font-size: @font-size-base; +@breadcrumb-link-color: @text-color-secondary; +@breadcrumb-link-color-hover: @primary-5; +@breadcrumb-separator-color: @text-color-secondary; +@breadcrumb-separator-margin: 0 @padding-xs; + +// Slider +// --- +@slider-margin: 14px 6px 10px; +@slider-rail-background-color: @background-color-base; +@slider-rail-background-color-hover: #e1e1e1; +@slider-track-background-color: @primary-3; +@slider-track-background-color-hover: @primary-4; +@slider-handle-color: @primary-3; +@slider-handle-color-hover: @primary-4; +@slider-handle-color-focus: tint(@primary-color, 20%); +@slider-handle-color-focus-shadow: fade(@primary-color, 20%); +@slider-handle-color-tooltip-open: @primary-color; +@slider-dot-border-color: @border-color-split; +@slider-dot-border-color-active: tint(@primary-color, 50%); +@slider-disabled-color: @disabled-color; +@slider-disabled-background-color: @component-background; + +// Tree +// --- +@tree-title-height: 24px; +@tree-child-padding: 18px; +@tree-directory-selected-color: #fff; +@tree-directory-selected-bg: @primary-color; +@tree-node-hover-bg: @item-hover-bg; +@tree-node-selected-bg: @primary-2; + +// Collapse +// --- +@collapse-header-padding: 12px 16px 12px 40px; +@collapse-header-bg: @background-color-light; +@collapse-content-padding: @padding-md; +@collapse-content-bg: @component-background; + +// Skeleton +// --- +@skeleton-color: #f2f2f2; + +// Transfer +// --- +@transfer-disabled-bg: @disabled-bg; + +// Message +// --- +@message-notice-content-padding: 10px 16px; + +// Motion +// --- +@wave-animation-width: 6px; + +// Alert +// --- +@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; +@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; +@alert-success-icon-color: @success-color; +@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; +@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; +@alert-info-icon-color: @info-color; +@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; +@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; +@alert-warning-icon-color: @warning-color; +@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; +@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; +@alert-error-icon-color: @error-color; + +// List +// --- +@list-header-background: transparent; +@list-footer-background: transparent; +@list-empty-text-padding: @padding-md; +@list-item-padding: @padding-sm 0; +@list-item-meta-margin-bottom: @padding-md; +@list-item-meta-avatar-margin-right: @padding-md; +@list-item-meta-title-margin-bottom: @padding-sm; + +// Statistic +// --- +@statistic-title-font-size: @font-size-base; +@statistic-content-font-size: 24px; +@statistic-unit-font-size: 16px; +@statistic-font-family: @font-family; + +// Drawer +// --- +@drawer-header-padding: 16px 24px; +@drawer-body-padding: 24px; + +// Typography +// --- +@typography-title-font-weight: 600; diff --git a/zeppelin-web-angular/src/styles/theme/markdown.less b/zeppelin-web-angular/src/styles/theme/markdown.less new file mode 100644 index 00000000000..d9f26833d6e --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/markdown.less @@ -0,0 +1,166 @@ +/* + * 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. + */ + +.markdown-body { + color: @text-color; + font-size: 14px; + line-height: 1.5; + + h1 { + color: @heading-color; + font-weight: 500; + margin: 0.6em 0 0.6em; + font-family: Avenir, @font-family; + font-size: 30px; + font-variant: tabular-nums; + line-height: 38px; + } + + h2 { + font-size: 24px; + line-height: 32px; + } + + h2, + h3, + h4, + h5, + h6 { + color: @heading-color; + font-family: Avenir, @font-family; + font-variant: tabular-nums; + margin: 0.6em 0 0.6em; + font-weight: 500; + clear: both; + } + + h3 { + font-size: 18px; + } + + h4 { + font-size: 16px; + } + + h5 { + font-size: 14px; + } + + h6 { + font-size: 12px; + } + + hr { + height: 1px; + border: 0; + background: @border-color-split; + margin: 56px 0; + clear: both; + } + + p, + pre { + margin: 1em 0; + } + + ul > li { + list-style-type: circle; + margin-left: 20px; + padding-left: 4px; + + &:empty { + display: none; + } + } + + ol > li { + list-style-type: decimal; + margin-left: 20px; + padding-left: 4px; + } + + ul > li > p, + ol > li > p { + margin: 0.2em 0; + } + + code { + margin: 0 1px; + background: #f2f4f5; + padding: .2em .4em; + border-radius: 3px; + font-size: .9em; + border: 1px solid #eee; + } + + pre { + border-radius: @border-radius-sm; + background: #f2f4f5; + font-family: "Lucida Console", Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + } + + pre code { + border: none; + background: #f2f4f5; + margin: 0; + padding: 0; + font-size: @font-size-base - 1px; + color: @text-color; + overflow: auto; + } + + strong, + b { + font-weight: 500; + } + + > table { + border-collapse: collapse; + border-spacing: 0; + empty-cells: show; + border: 1px solid @border-color-split; + width: 100%; + margin: 8px 0 16px; + } + + > table th { + white-space: nowrap; + color: #5c6b77; + font-weight: 500; + background: rgba(0, 0, 0, 0.02); + } + + & > table th, + & > table td { + border: 1px solid @border-color-split; + padding: 16px 24px; + text-align: left; + } + + blockquote { + font-size: 90%; + color: @text-color-secondary; + border-left: 4px solid @border-color-split; + padding-left: 0.8em; + margin: 1em 0; + } + + blockquote p { + margin: 0; + } + + & > br, + & > p > br { + clear: both; + } + +} diff --git a/zeppelin-web-angular/src/styles/theme/theme-mixin.less b/zeppelin-web-angular/src/styles/theme/theme-mixin.less new file mode 100644 index 00000000000..4daec305409 --- /dev/null +++ b/zeppelin-web-angular/src/styles/theme/theme-mixin.less @@ -0,0 +1,24 @@ +/* + * 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 '../../../node_modules/ng-zorro-antd/src/style/color/colors'; + +.themeMixin(@rules) { + :host-context(.light) { + @import 'theme-light'; + @rules(); + } + :host-context(.dark) { + @import 'theme-dark'; + @rules(); + } +} diff --git a/zeppelin-web-angular/src/test.ts b/zeppelin-web-angular/src/test.ts new file mode 100644 index 00000000000..f90345f8e54 --- /dev/null +++ b/zeppelin-web-angular/src/test.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import { getTestBed } from '@angular/core/testing'; +import { platformBrowserDynamicTesting, BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; +// tslint:disable-next-line:no-import-side-effect +import 'zone.js/dist/zone-testing'; + +// tslint:disable-next-line no-any +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting()); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/zeppelin-web-angular/src/tsconfig.app.json b/zeppelin-web-angular/src/tsconfig.app.json new file mode 100644 index 00000000000..50958688dbe --- /dev/null +++ b/zeppelin-web-angular/src/tsconfig.app.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": ["mathjax"] + }, + "exclude": ["test.ts", "**/*.spec.ts"] +} diff --git a/zeppelin-web-angular/src/tsconfig.spec.json b/zeppelin-web-angular/src/tsconfig.spec.json new file mode 100644 index 00000000000..70add2d529d --- /dev/null +++ b/zeppelin-web-angular/src/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": ["jasmine", "node"] + }, + "files": ["test.ts", "polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] +} diff --git a/zeppelin-web-angular/src/tslint.json b/zeppelin-web-angular/src/tslint.json new file mode 100644 index 00000000000..bb3e34a7b6e --- /dev/null +++ b/zeppelin-web-angular/src/tslint.json @@ -0,0 +1,7 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [true, "attribute", "zeppelin", "camelCase"], + "component-selector": [true, "element", "zeppelin", "kebab-case"] + } +} diff --git a/zeppelin-web-angular/tsconfig.app.json b/zeppelin-web-angular/tsconfig.app.json new file mode 100644 index 00000000000..565a11a2156 --- /dev/null +++ b/zeppelin-web-angular/tsconfig.app.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/test.ts", + "src/**/*.spec.ts" + ] +} diff --git a/zeppelin-web-angular/tsconfig.json b/zeppelin-web-angular/tsconfig.json new file mode 100644 index 00000000000..45f06cbf7de --- /dev/null +++ b/zeppelin-web-angular/tsconfig.json @@ -0,0 +1,47 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "paths": { + "@zeppelin/*": [ + "./src/app/*", + "./src/environments/*" + ], + "@zeppelin/helium": [ + "./dist/zeppelin-helium" + ], + "@zeppelin/helium/*": [ + "./dist/zeppelin-helium/*" + ], + "@zeppelin/visualization": [ + "dist/zeppelin-visualization" + ], + "@zeppelin/visualization/*": [ + "dist/zeppelin-visualization/*" + ], + "@zeppelin/sdk": [ + "dist/zeppelin-sdk" + ], + "@zeppelin/sdk/*": [ + "dist/zeppelin-sdk/*" + ] + }, + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "module": "esnext", + "moduleResolution": "node", + "importHelpers": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + } +} \ No newline at end of file diff --git a/zeppelin-web-angular/tsconfig.spec.json b/zeppelin-web-angular/tsconfig.spec.json new file mode 100644 index 00000000000..6400fde7d54 --- /dev/null +++ b/zeppelin-web-angular/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/zeppelin-web-angular/tslint.json b/zeppelin-web-angular/tslint.json new file mode 100644 index 00000000000..74aed2552ed --- /dev/null +++ b/zeppelin-web-angular/tslint.json @@ -0,0 +1,141 @@ +{ + "rulesDirectory": ["node_modules/codelyzer"], + "rules": { + "banana-in-box": true, + "templates-no-negated-async": true, + "no-life-cycle-call": false, + "prefer-output-readonly": true, + "no-conflicting-life-cycle-hooks": false, + "enforce-component-selector": false, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": false, + "use-view-encapsulation": false, + "no-attribute-parameter-decorator": true, + "no-output-named-after-standard-event": true, + "no-output-rename": true, + "no-output-on-prefix": true, + "no-forward-ref": false, + "use-life-cycle-interface": true, + "contextual-life-cycle": true, + "trackBy-function": false, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true, + "pipe-impure": true, + "angular-whitespace": [false, "check-interpolation"], + "directive-selector": [true, "attribute", ["zeppelin"], ["camelCase", "kebab-case"]], + "component-selector": [true, ["element", "attribute"], ["zeppelin"], "kebab-case"], + "callable-types": true, + "class-name": true, + "comment-format": [true, "check-space"], + "align": [true, "parameters", "statements"], + "array-type": [true, "array-simple"], + "arrow-return-shorthand": true, + "ban-types": [ + true, + ["Object", "Use {} instead."], + ["String", "Use string instead."], + ["Number", "Use number instead."], + ["Boolean", "Use boolean instead."], + ["Function", "Use specific callable interface instead."] + ], + "binary-expression-operand-order": true, + "curly": true, + "encoding": true, + "eofline": true, + "deprecation": { + "severity": "warn" + }, + "import-spacing": true, + "indent": [true, "spaces"], + "interface-name": [true, "never-prefix"], + "interface-over-type-literal": true, + "label-position": true, + "new-parens": true, + "no-angle-bracket-type-assertion": true, + "member-access": false, + "member-ordering": [ + true, + { + "order": ["static-field", "instance-field", "static-method", "instance-method"] + } + ], + "no-any": true, + "no-arg": true, + "no-bitwise": false, + "no-consecutive-blank-lines": [true], + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-duplicate-variable": true, + "no-conditional-assignment": true, + "no-construct": true, + "no-debugger": true, + "no-duplicate-imports": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-floating-promises": false, + "no-for-in-array": true, + "no-import-side-effect": true, + "no-inferrable-types": [true, "ignore-params", "ignore-properties"], + "no-invalid-template-strings": true, + "no-invalid-this": true, + "no-irregular-whitespace": true, + "no-magic-numbers": false, + "no-misused-new": true, + "no-namespace": [true, "allow-declarations"], + "no-non-null-assertion": false, + "no-shadowed-variable": true, + "no-sparse-arrays": true, + "no-string-literal": true, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-this-assignment": true, + "no-trailing-whitespace": true, + "no-parameter-reassignment": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "number-literal-format": true, + "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], + "one-variable-per-declaration": [true, "ignore-for-loop"], + "ordered-imports": [ + true, + { + "import-sources-order": "lowercase-last", + "named-imports-order": "lowercase-first" + } + ], + "prefer-conditional-expression": false, + "prefer-const": true, + "prefer-method-signature": true, + "prefer-object-spread": true, + "prefer-template": [true, "allow-single-concat"], + "radix": true, + "trailing-comma": [ + true, + { + "multiline": "never", + "singleline": "never" + } + ], + "triple-equals": [true, "allow-null-check"], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "unified-signatures": true, + "use-isnan": true, + "variable-name": [true, "ban-keywords", "allow-leading-underscore"], + "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"], + "no-input-rename": true + } +} diff --git a/zeppelin-web-angular/webpack.partial.js b/zeppelin-web-angular/webpack.partial.js new file mode 100644 index 00000000000..c2261441f9c --- /dev/null +++ b/zeppelin-web-angular/webpack.partial.js @@ -0,0 +1,27 @@ +/* + * 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. + */ + +const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); + +module.exports = { + plugins: [ + new MonacoWebpackPlugin({ + languages: [ + 'bat', 'cpp', 'csharp', 'csp', 'css', 'dockerfile', 'go', 'handlebars', 'html', 'java', 'javascript', 'json', + 'less', 'lua', 'markdown', 'mysql', 'objective', 'perl', 'pgsql', 'php', 'powershell', 'python', 'r', 'ruby', + 'rust', 'scheme', 'scss', 'shell', 'sql', 'swift', 'typescript', 'vb', 'xml', 'yaml' + ], + features: ['!accessibilityHelp'] + }) + ] +}; + From d3979c2709d95ff17a10f3f3bbca91150f645a78 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Fri, 8 Nov 2019 17:20:59 +0800 Subject: [PATCH 08/32] [ZEPPELIN-4321] Support shortcuts for the paragraphs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? We are using Angular Latest to refactor Zeppelin's front-end. When implementing the features of the shortcuts, we found that the current shortcuts is somewhat complicated and did not distinguish the Command/Ctrl key between Mac and Windows. So we compared the following applications: - [Jupyter](https://github.com/jupyter/jupyter) - [JupyterLab](https://github.com/jupyterlab/jupyterlab) - [Google Colaboratory](https://colab.research.google.com/) They can distinguish between edit-mode and command-mode, which will simplify the shortcuts complexity. Meanwhile, we use the [Monaco editor](https://github.com/microsoft/monaco-editor) in the refactor version, it is the core library of [VSCode](https://github.com/microsoft/vscode). We think it is a good choice to use its shortcuts design. Therefore, for the above reasons, we proposed to redesign Zeppelin's shortcuts according to the table following. | Actions | Mode | Mac | Windows / Linux | Old(Mac) | |-------------------------------------------------------|---------|------------------|-----------------------|------------------| | Command mode | Edit | ESC | ESC | - | | Edit mode | Command | Enter | Enter | - | | Run | - | ⇧ + Enter | ⇧ + Enter | ⇧ + Enter | | Run all below | - | ⇧ + ⌘ + Enter | ⇧ + Ctrl + Enter | ⇧ + Ctrl + Enter | | Run all above | - | ⇧ + ⌥ + Enter | ⇧ + Alt + Enter | ⇧ + Ctrl + Enter | | Cancel | - | ⇧ + ⌘ + C | ⇧ + Ctrl + C | ⌥ + Ctrl + C | | Switch all line number | - | ⇧ + ⌘ + L | ⇧ + Ctrl + L | - | | Show / Hide all output | - | ⇧ + ⌘ + O | ⇧ + Ctrl + O | - | | Show / Hide all title | - | ⇧ + ⌘ + T | ⇧ + Ctrl + T | - | | Clear output | - | ⌘ + ⌥ + L | Ctrl + Alt + L | ⌥ + Ctrl + L | | Enable/Disable | - | ⌘ + ⌥ + R | Ctrl + Alt + R | ⌥ + Ctrl + R | | Reduce width | - | ⌘ + ⌥ + + | Ctrl + Alt + - | ⇧ + Ctrl + - | | Increase width | - | ⌘ + ⌥ + - | Ctrl + Alt + + | ⇧ + Ctrl + + | | Delete | Command | ⇧ + Del | ⇧ + Del | ⌥ + Ctrl + D | | Move to up | Command | ⌘ + K / Up | Ctrl + K / Up | ⌥ + Ctrl + K | | Move to down | Command | ⌘ + J / Down | Ctrl + J / Down | ⌥ + Ctrl + J | | Select above | Command | K / Up | K / Up | - | | Select below | Command | J / Down | J / Down | - | | Switch line number | Command | L | L | ⌥ + Ctrl + M | | Show / Hide title | Command | T | T | ⌥ + Ctrl + T | | Show / Hide output | Command | O | O | ⌥ + Ctrl + O | | Show / Hide editor | Command | E | E | ⌥ + Ctrl + E | | Insert above | Command | A | A | ⌥ + Ctrl + A | | Insert below | Command | B | B | ⌥ + Ctrl + B | | Search | Edit | ⌘ + F | Ctrl + F | ⌥ + Ctrl + F | | Increase Indent | Edit | Tab | Tab | - | | Decrease Indent | Edit | ⇧ + Tab | ⇧ + Tab | - | | Comment Out / In | Edit | ⌘ + / | Ctrl + / | Ctrl + / | | Undo | Edit | ⌘ + Z | Ctrl + Z | Ctrl + Z | | Redo | Edit | ⇧ + ⌘ + Z | Ctrl + Y | - | | Increase font size | Edit | ⌘ + . | Ctrl + . | - | | Decrease font size | Edit | ⌘ + , | Ctrl + , | - | | Decrease Indent | Edit | ⌘ + [ | Ctrl + [ | - | | Increase Indent | Edit | ⌘ + ] | Ctrl + ] | - | | Move the line down | Edit | ⌥ + Down | Alt + Down | ⌥ + Down | | Move the line up | Edit | ⌥ + Up | Alt + Up | ⌥ + Down | | Replace | Edit | ⌘ + ⌥ + F | Ctrl + F | - | | Select all | Edit | ⌘ + A | Ctrl + A | ⌘ + A | | Select downward | Edit | ⇧ + Down | ⇧ + Down | ⇧ + Down | | Select right | Edit | ⇧ + Right | ⇧ + Right | ⇧ + Right | | Select left | Edit | ⇧ + Left | ⇧ + Left | ⇧ + Left | | Select upward | Edit | ⇧ + Up | ⇧ + Up | ⇧ + Up | | Select to the end | Edit | ⌘ + ⇧ + Right | Alt + ⇧ + Right | ⌘ + ⇧ + Right | | Select to the start | Edit | ⌘ + ⇧ + Left | Alt + ⇧ + Left | ⌘ + ⇧ + Left | | Align text right | Edit | ⌥ + Right | Ctrl + ⇧ + Right | ⌥ + Right | | Align text left | Edit | ⌥ + Left | Ctrl + ⇧ + Left | ⌥ + Left | | Add multi-cursor above | Edit | ⌘ + ⌥ + Up | Ctrl + Alt + Up | - | | Add multi-cursor below | Edit | ⌘ + ⌥ + Down | Ctrl + Alt + Down | - | | Move multi-cursor from current line to the line above | Edit | ⌘ + ⌥ + ⇧ + Up | Ctrl + Alt + ⇧ + Up | - | | Move multi-cursor from current line to the line below | Edit | ⌘ + ⌥ + ⇧ + Down | Ctrl + Alt + ⇧ + Down | - | ### What type of PR is it? [Feature] ### Todos * [ ] - Task ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4402 https://issues.apache.org/jira/browse/ZEPPELIN-4321 ### How should this be tested? * First time? Setup Travis CI as described on https://zeppelin.apache.org/contribution/contributions.html#continuous-integration * Strongly recommended: add automated unit tests for any new or changed behavior * Outline any manual steps to test the PR here. ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3517 from hsuanxyz/feat/hot-key and squashes the following commits: 0dec67601 [Hsuan Lee] feat(paragraph): support shortcut --- zeppelin-web-angular/package-lock.json | 76 ++++-- zeppelin-web-angular/package.json | 6 +- .../notebook/notebook.component.html | 6 +- .../workspace/notebook/notebook.component.ts | 16 +- .../code-editor/code-editor.component.ts | 13 + .../paragraph/control/control.component.ts | 24 +- .../paragraph/paragraph.component.html | 9 +- .../paragraph/paragraph.component.less | 5 + .../notebook/paragraph/paragraph.component.ts | 227 +++++++++++++++++- .../paragraph/result/result.component.ts | 3 + .../src/app/services/public-api.ts | 1 + .../src/app/services/shortcut.service.ts | 109 +++++++++ 12 files changed, 436 insertions(+), 59 deletions(-) create mode 100644 zeppelin-web-angular/src/app/services/shortcut.service.ts diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index 46c0a074b8d..85ad2a6251f 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -6852,23 +6852,54 @@ } }, "husky": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-2.7.0.tgz", - "integrity": "sha512-LIi8zzT6PyFpcYKdvWRCn/8X+6SuG2TgYYMrM6ckEYhlp44UcEduVymZGIZNLiwOUjrEud+78w/AsAiqJA/kRg==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/husky/-/husky-3.0.9.tgz", + "integrity": "sha512-Yolhupm7le2/MqC1VYLk/cNmYxsSsqKkTyBhzQHhPK1jFnC89mmmNVuGtLNabjDI6Aj8UNIr0KpRNuBkiC4+sg==", "dev": true, "requires": { - "cosmiconfig": "^5.2.0", + "chalk": "^2.4.2", + "ci-info": "^2.0.0", + "cosmiconfig": "^5.2.1", "execa": "^1.0.0", - "find-up": "^3.0.0", "get-stdin": "^7.0.0", - "is-ci": "^2.0.0", - "pkg-dir": "^4.1.0", - "please-upgrade-node": "^3.1.1", - "read-pkg": "^5.1.1", + "opencollective-postinstall": "^2.0.2", + "pkg-dir": "^4.2.0", + "please-upgrade-node": "^3.2.0", + "read-pkg": "^5.2.0", "run-node": "^1.0.0", "slash": "^3.0.0" }, "dependencies": { + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -6900,18 +6931,6 @@ "dev": true, "requires": { "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - } } }, "slash": { @@ -6919,6 +6938,15 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -10409,6 +10437,12 @@ "is-wsl": "^1.1.0" } }, + "opencollective-postinstall": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", + "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", + "dev": true + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index ae96fe7f87b..63b6be17d43 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -44,8 +44,6 @@ "zone.js": "~0.9.1" }, "devDependencies": { - "monaco-editor-webpack-plugin": "^1.7.0", - "ngx-build-plus": "^8.1.5", "@angular-devkit/build-angular": "^0.803.9", "@angular-devkit/build-ng-packagr": "~0.803.6", "@angular/cli": "~8.3.9", @@ -61,7 +59,7 @@ "codelyzer": "^5.0.0", "dotenv": "^8.0.0", "https-proxy-agent": "^2.2.1", - "husky": "^2.2.0", + "husky": "^3.0.9", "jasmine-core": "~3.4.0", "jasmine-spec-reporter": "~4.2.1", "karma": "~4.1.0", @@ -70,7 +68,9 @@ "karma-jasmine": "~2.0.1", "karma-jasmine-html-reporter": "^1.4.0", "lint-staged": "^8.1.6", + "monaco-editor-webpack-plugin": "^1.7.0", "ng-packagr": "^5.4.0", + "ngx-build-plus": "^8.1.5", "prettier": "^1.17.0", "protractor": "~5.4.0", "ts-node": "~7.0.0", diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html index 3bad5eec173..c447a59c39d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -36,8 +36,10 @@
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index a894971b8e9..97479a70938 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -21,7 +21,7 @@ import { } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { isNil } from 'lodash'; -import { Subject } from 'rxjs'; +import { Subject} from 'rxjs'; import { distinctUntilKeyChanged, takeUntil } from 'rxjs/operators'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; @@ -48,6 +48,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit private destroy$ = new Subject(); note: Note['note']; permissions: Permissions; + selectId: string | null = null; isOwner = true; noteRevisions: RevisionListItem[] = []; currentRevision: string; @@ -216,6 +217,17 @@ export class NotebookComponent extends MessageListenersManager implements OnInit }, 10000); } + onParagraphSelect(id: string) { + this.selectId = id; + } + + onSelectAtIndex(index: number) { + const scopeIndex = Math.min(this.note.paragraphs.length, Math.max(0, index)); + if (this.note.paragraphs[scopeIndex]) { + this.selectId = this.note.paragraphs[scopeIndex].id; + } + } + saveNote() { if (this.note && this.note.paragraphs && this.listOfNotebookParagraphComponent) { this.listOfNotebookParagraphComponent.toArray().forEach(p => { @@ -276,7 +288,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit private noteVarShareService: NoteVarShareService, private ticketService: TicketService, private securityService: SecurityService, - private router: Router + private router: Router, ) { super(messageService); } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index 6dabb4b2bbc..0711e816542 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -55,6 +55,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro @Input() pid: string; @Output() readonly textChanged = new EventEmitter(); @Output() readonly editorBlur = new EventEmitter(); + @Output() readonly editorFocus = new EventEmitter(); private editor: IStandaloneCodeEditor; private monacoDisposables: IDisposable[] = []; height = 0; @@ -76,6 +77,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro this.monacoDisposables.push( editor.onDidFocusEditorText(() => { this.ngZone.runOutsideAngular(() => { + this.editorFocus.emit(); editor.updateOptions({ renderLineHighlight: 'all' }); }); }), @@ -85,6 +87,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro editor.updateOptions({ renderLineHighlight: 'none' }); }); }), + editor.onDidChangeModelContent(() => { this.ngZone.run(() => { this.text = editor.getModel().getValue(); @@ -123,6 +126,16 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro }); } + this.editor.addCommand( + monaco.KeyCode.Escape, + () => { + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur(); + } + }, + '!suggestWidgetVisible' + ); + this.updateEditorOptions(); this.setParagraphMode(); this.initEditorListener(); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts index 085fa266b2e..5b959539d92 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -71,6 +71,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { @Output() readonly runAllAbove = new EventEmitter(); @Output() readonly runAllBelowAndCurrent = new EventEmitter(); @Output() readonly cloneParagraph = new EventEmitter(); + @Output() readonly removeParagraph = new EventEmitter(); fontSizeOption = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; dropdownVisible = false; isMac = navigator.appVersion.indexOf('Mac') !== -1; @@ -190,7 +191,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { show: this.paragraphLength > 1, disabled: this.isEntireNoteRunning, icon: 'delete', - trigger: () => this.removeParagraph(), + trigger: () => this.onRemoveParagraph(), shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+D`, keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_D] : [] } @@ -258,25 +259,8 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { } } - removeParagraph() { - if (!this.isEntireNoteRunning) { - if (this.paragraphLength === 1) { - this.nzModalService.warning({ - nzTitle: `Warning`, - nzContent: `All the paragraphs can't be deleted` - }); - } else { - this.nzModalService.confirm({ - nzTitle: 'Delete Paragraph', - nzContent: 'Do you want to delete this paragraph?', - nzOnOk: () => { - this.messageService.paragraphRemove(this.pid); - this.cdr.markForCheck(); - // TODO(hsuanxyz) moveFocusToNextParagraph - } - }); - } - } + onRemoveParagraph() { + this.removeParagraph.emit(); } trigger(event: EventEmitter) { diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html index 861f955e261..1c42f87b371 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -14,7 +14,10 @@ -
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less index f24d693f1e8..60cc5ac3b19 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.less @@ -18,6 +18,7 @@ } .themeMixin({ + .paragraph { background: @component-background; border: 1px solid @border-color-split; @@ -25,6 +26,10 @@ padding: 32px 12px 12px 12px; position: relative; + &.focused { + box-shadow: 0 0 5px rgba(0, 0, 0, 0.46); + } + zeppelin-notebook-paragraph-code-editor + zeppelin-notebook-paragraph-dynamic-forms { margin-top: 24px; } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index 21d57bb6e17..1dde62dae65 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -13,7 +13,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, + Component, ElementRef, EventEmitter, Input, OnChanges, @@ -21,15 +21,16 @@ import { OnInit, Output, QueryList, + SimpleChanges, ViewChild, ViewChildren } from '@angular/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import {merge, Observable, Subject} from 'rxjs'; +import {map, takeUntil} from 'rxjs/operators'; import DiffMatchPatch from 'diff-match-patch'; import { isEmpty, isEqual } from 'lodash'; -import { NzModalService } from 'ng-zorro-antd'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { @@ -52,7 +53,10 @@ import { NgZService, NoteStatusService, NoteVarShareService, - ParagraphStatus + ParagraphActions, + ParagraphStatus, + ShortcutsMap, + ShortcutService } from '@zeppelin/services'; import { SpellResult } from '@zeppelin/spell/spell-result'; @@ -60,10 +64,16 @@ import { NzResizeEvent } from 'ng-zorro-antd/resizable'; import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component'; import { NotebookParagraphResultComponent } from './result/result.component'; +type Mode = 'edit' | 'command'; + @Component({ selector: 'zeppelin-notebook-paragraph', templateUrl: './paragraph.component.html', styleUrls: ['./paragraph.component.less'], + host: { + 'tabindex': '-1', + '(focusin)': 'onFocus()' + }, changeDetection: ChangeDetectionStrategy.OnPush }) export class NotebookParagraphComponent extends MessageListenersManager implements OnInit, OnChanges, OnDestroy { @@ -76,6 +86,8 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen @Input() note: Note['note']; @Input() looknfeel: string; @Input() revisionView: boolean; + @Input() select: boolean = false; + @Input() index: number = -1; @Input() viewOnly: boolean; @Input() last: boolean; @Input() collaborativeMode = false; @@ -83,8 +95,12 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen @Input() interpreterBindings: InterpreterBindingItem[] = []; @Output() readonly saveNoteTimer = new EventEmitter(); @Output() readonly triggerSaveParagraph = new EventEmitter(); + @Output() readonly selected = new EventEmitter(); + @Output() readonly selectAtIndex = new EventEmitter(); private destroy$ = new Subject(); + private mode: Mode = 'command'; + waitConfirmFromEdit = false; dirtyText: string; originalText: string; isEntireNoteRunning = false; @@ -185,6 +201,19 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen } } + switchMode(mode: Mode): void { + if (mode === this.mode) { + return; + } + this.mode = mode; + if (mode === 'edit') { + this.focusEditor(); + } else { + this.blurEditor(); + (this.host.nativeElement as HTMLElement).focus(); + } + } + updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) { // 1. can't update on revision view if (!this.revisionView) { @@ -237,6 +266,34 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen this.saveNoteTimer.emit(); } + onFocus() { + this.selected.emit(this.paragraph.id); + } + + focusEditor() { + this.paragraph.focus = true; + this.saveParagraph(); + this.cdr.markForCheck(); + } + + blurEditor() { + this.paragraph.focus = false; + (this.host.nativeElement as HTMLElement).focus(); + this.saveParagraph(); + this.cdr.markForCheck(); + } + + onEditorFocus() { + this.switchMode('edit'); + } + + onEditorBlur() { + // Ignore events triggered by open the confirm box in edit mode + if (!this.waitConfirmFromEdit) { + this.switchMode('command'); + } + } + saveParagraph() { const dirtyText = this.paragraph.text; if (dirtyText === undefined || dirtyText === this.originalText) { @@ -248,6 +305,27 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen this.cdr.markForCheck(); } + removeParagraph() { + if (!this.isEntireNoteRunning) { + if (this.note.paragraphs.length === 1) { + this.nzModalService.warning({ + nzTitle: `Warning`, + nzContent: `All the paragraphs can't be deleted` + }); + } else { + this.nzModalService.confirm({ + nzTitle: 'Delete Paragraph', + nzContent: 'Do you want to delete this paragraph?', + nzOnOk: () => { + this.messageService.paragraphRemove(this.paragraph.id); + this.cdr.markForCheck(); + // TODO(hsuanxyz) moveFocusToNextParagraph + } + }); + } + } + } + runAllAbove() { const index = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id); const toRunParagraphs = this.note.paragraphs.filter((p, i) => i < index); @@ -298,7 +376,11 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen nzOnOk: () => { this.messageService.runAllParagraphs(this.note.id, paragraphs); } - }); + }).afterClose + .pipe(takeUntil(this.destroy$)) + .subscribe(() => { + this.waitConfirmFromEdit = false; + }); // TODO(hsuanxyz): save cursor } @@ -486,7 +568,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen setTitle(title: string) { this.paragraph.title = title; this.commitParagraph(); - this.cdr.markForCheck(); } commitParagraph() { @@ -498,6 +579,7 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen settings: { params } } = this.paragraph; this.messageService.commitParagraph(id, title, text, config, params, this.note.id); + this.cdr.markForCheck(); } initializeDefault(config: ParagraphConfig) { @@ -586,7 +668,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen onConfigChange(configResult: ParagraphConfigResult, index: number) { this.paragraph.config.results[index] = configResult; this.commitParagraph(); - this.cdr.markForCheck(); } setEditorHide(editorHide: boolean) { @@ -610,12 +691,128 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen private nzModalService: NzModalService, private noteVarShareService: NoteVarShareService, private cdr: ChangeDetectorRef, - private ngZService: NgZService + private ngZService: NgZService, + private shortcutService: ShortcutService, + private host: ElementRef ) { super(messageService); } ngOnInit() { + const shortcutService = this.shortcutService.forkByElement(this.host.nativeElement); + const observables: Array> = []; + Object.entries(ShortcutsMap).forEach(([action, keys]) => { + const keysArr: string[] = Array.isArray(keys) ? keys : [keys]; + keysArr.forEach(key => { + observables.push( + shortcutService.bindShortcut({ + keybindings: key + }).pipe( + takeUntil(this.destroy$), + map(({event}) => { + return { + event, + action: action as ParagraphActions + } + })) + ); + }); + }); + + merge<{ + action: ParagraphActions, + event: KeyboardEvent + }>(...observables) + .pipe(takeUntil(this.destroy$)) + .subscribe(({action, event}) => { + if (this.mode === 'command') { + switch (action) { + case ParagraphActions.InsertAbove: + this.insertParagraph('above'); + break; + case ParagraphActions.InsertBelow: + this.insertParagraph('below'); + break; + case ParagraphActions.SwitchEditorShow: + this.setEditorHide(!this.paragraph.config.editorHide); + this.commitParagraph(); + break; + case ParagraphActions.SwitchOutputShow: + this.setTableHide(!this.paragraph.config.tableHide); + this.commitParagraph(); + break; + case ParagraphActions.SwitchTitleShow: + this.paragraph.config.title = !this.paragraph.config.title; + this.commitParagraph(); + break; + case ParagraphActions.SwitchLineNumber: + this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers; + this.commitParagraph(); + break; + case ParagraphActions.MoveToUp: + this.moveUpParagraph(); + break; + case ParagraphActions.MoveToDown: + this.moveDownParagraph(); + break; + case ParagraphActions.SwitchEnable: + this.paragraph.config.enabled = !this.paragraph.config.enabled; + this.commitParagraph(); + break; + case ParagraphActions.ReduceWidth: + this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.IncreaseWidth: + this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.Delete: + this.removeParagraph(); + break; + case ParagraphActions.SelectAbove: + event.preventDefault(); + this.selectAtIndex.emit(this.index - 1); + break; + case ParagraphActions.SelectBelow: + event.preventDefault(); + this.selectAtIndex.emit(this.index + 1); + break; + default: + break; + } + } + switch (action) { + case ParagraphActions.EditMode: + if (this.mode === 'command') { + event.preventDefault(); + } + if (!this.paragraph.config.editorHide) { + this.switchMode('edit'); + } + break; + case ParagraphActions.Run: + event.preventDefault(); + this.runParagraph(); + break; + case ParagraphActions.RunBelow: + this.waitConfirmFromEdit = true; + this.runAllBelowAndCurrent(); + break; + case ParagraphActions.Cancel: + event.preventDefault(); + this.cancelParagraph(); + break; + default: + break; + } + }); + this.setResults(); this.originalText = this.paragraph.text; this.isEntireNoteRunning = this.noteStatusService.isEntireNoteRunning(this.note); @@ -644,7 +841,17 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen }); } - ngOnChanges(): void {} + ngOnChanges(changes: SimpleChanges): void { + const { index, select } = changes; + if (index && index.currentValue !== index.previousValue && this.select + || select && select.currentValue === true && select.previousValue !== true) { + if (this.host.nativeElement) { + setTimeout(() => { + (this.host.nativeElement as HTMLElement).focus(); + }) + } + } + } ngOnDestroy(): void { super.ngOnDestroy(); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts index 850bc18a394..903f72bccc5 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts @@ -254,6 +254,9 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, } setGraphConfig() { + if (!this.config || !this.config.graph) { + return; + } const visualizationItem = this.visualizations.find(v => v.id === this.config.graph.mode); if (!visualizationItem || !visualizationItem.instance) { return; diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts index d56ec7e5c6f..d6709ac83e8 100644 --- a/zeppelin-web-angular/src/app/services/public-api.ts +++ b/zeppelin-web-angular/src/app/services/public-api.ts @@ -26,3 +26,4 @@ export * from './ng-z.service'; export * from './array-ordering.service'; export * from './note-list.service'; export * from './runtime-compiler.service'; +export * from './shortcut.service'; diff --git a/zeppelin-web-angular/src/app/services/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts new file mode 100644 index 00000000000..b6d6a3aac18 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts @@ -0,0 +1,109 @@ +import {DOCUMENT} from "@angular/common"; +import {Inject, Injectable} from '@angular/core'; +import {EventManager} from "@angular/platform-browser"; +import {Observable} from "rxjs"; + +export enum ParagraphActions { + EditMode = 'Paragraph:EditMode', + CommandMode = 'Paragraph:CommandMode', + Run = 'Paragraph:Run', + RunBelow = 'Paragraph:RunBelow', + Cancel = 'Paragraph:Cancel', + Clear = 'Paragraph:Clear', + ReduceWidth = 'Paragraph:ReduceWidth', + IncreaseWidth = 'Paragraph:IncreaseWidth', + Delete = 'Paragraph:Delete', + MoveToUp = 'Paragraph:MoveToUp', + MoveToDown = 'Paragraph:MoveToDown', + SelectAbove = 'Paragraph:SelectAbove', + SelectBelow = 'Paragraph:SelectBelow', + InsertAbove = 'Paragraph:InsertAbove', + InsertBelow = 'Paragraph:InsertBelow', + SwitchLineNumber = 'Paragraph:SwitchLineNumber', + SwitchTitleShow = 'Paragraph:SwitchTitleShow', + SwitchOutputShow = 'Paragraph:SwitchOutputShow', + SwitchEditorShow = 'Paragraph:SwitchEditorShow', + SwitchEnable = 'Paragraph:SwitchEnable' +} + +export const ShortcutsMap = { + [ParagraphActions.EditMode]: 'enter', + [ParagraphActions.CommandMode]: 'esc', + [ParagraphActions.Run]: 'shift.enter', + [ParagraphActions.RunBelow]: 'shift.ctrlCmd.enter', + [ParagraphActions.Cancel]: 'shift.ctrlCmd.c', + // Need register special character `¬` in MacOS + [ParagraphActions.Clear]: ['alt.ctrlCmd.l', 'alt.ctrlCmd.¬'], + // Need register special character `®` in MacOS + [ParagraphActions.SwitchEnable]: ['alt.ctrlCmd.r', 'alt.ctrlCmd.®'], + // Need register special character `–` in MacOS + [ParagraphActions.ReduceWidth]: ['alt.ctrlCmd.-', 'alt.ctrlCmd.–'], + // Need register special character `≠` in MacOS + [ParagraphActions.IncreaseWidth]: ['alt.ctrlCmd.+', 'alt.ctrlCmd.≠'], + [ParagraphActions.Delete]: 'shift.delete', + [ParagraphActions.MoveToUp]: ['ctrlCmd.k', 'ctrlCmd.arrowup'], + [ParagraphActions.MoveToDown]: ['ctrlCmd.j', 'ctrlCmd.arrowdown'], + [ParagraphActions.SelectAbove]: ['k', 'arrowup'], + [ParagraphActions.SelectBelow]: ['j', 'arrowdown'], + [ParagraphActions.SwitchLineNumber]: 'l', + [ParagraphActions.SwitchTitleShow]: 't', + [ParagraphActions.SwitchOutputShow]: 'o', + [ParagraphActions.SwitchEditorShow]: 'e', + [ParagraphActions.InsertAbove]: 'a', + [ParagraphActions.InsertBelow]: 'b' +}; + +export interface ShortcutEvent { + event: KeyboardEvent + keybindings: string; +} + +export interface ShortcutOption { + scope?: HTMLElement, + keybindings: string +} + +function isMacOS() { + return navigator.platform.indexOf('Mac') > -1 +} + +@Injectable({ + providedIn: 'root' +}) +export class ShortcutService { + + private element: HTMLElement; + + constructor(private eventManager: EventManager, + @Inject(DOCUMENT) _document: any) { + this.element = _document; + } + + forkByElement(element: HTMLElement) { + return new ShortcutService(this.eventManager, element); + } + + bindShortcut(option: ShortcutOption): Observable { + const host = option.scope || this.element; + // `ctrlCmd` is special symbol, will be replaced `meta` in MacOS, 'control' in Windows/Linux + const keybindings = option.keybindings + .replace(/ctrlCmd/g, isMacOS() ? 'meta' : 'control'); + const event = `keydown.${keybindings}`; + let dispose: Function; + return new Observable(observer => { + const handler = event => { + observer.next({ + event, + keybindings: option.keybindings + }); + }; + + dispose = this.eventManager.addEventListener(host, event, handler); + + return () => { + dispose(); + }; + }) + } + +} From 1e0177d132f8458aa6beff570c380b7b4740399f Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Tue, 26 Nov 2019 11:28:28 +0800 Subject: [PATCH 09/32] [ZEPPELIN-4450] Provide Angular.js Template Migration Tool ### What is this PR for? We have implemented the frontend API of Angular.js using the latest Angular. But the templates some [differences](https://angular.io/guide/ajs-quick-reference) between Angular.js and Angular. So to help users migrate templates, we provide a migration tool that will be integrated into the Zeppelin web. This is its [DEMO](https://ng1-updater.hsuan.xyz/) it can quickly fix these differences. We plan to do the following work: 1. Add a new type `%ng` (official abbreviation) to distinguish between Angular.js and Angular templates. 2. When the user runs a paragraph with the `%angular` type, the upgrade dialog will be open. 3. Upgrade the template in the dialog and click the `Update and Copy` button. 4. Automatically create a paragraph of type `%ng` template in below ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4321 https://issues.apache.org/jira/browse/ZEPPELIN-4450 ### How should this be tested? * First time? Setup Travis CI as described on https://zeppelin.apache.org/contribution/contributions.html#continuous-integration * Strongly recommended: add automated unit tests for any new or changed behavior * Outline any manual steps to test the PR here. ### Screenshots (if appropriate) ![ng1-template](https://user-images.githubusercontent.com/22736418/69597301-78de3000-1040-11ea-85a6-830d573f1305.gif) ### Questions: * Does the licenses files need update? NO * Is there breaking changes for older versions? NO * Does this needs documentation? NO Author: Hsuan Lee Closes #3528 from hsuanxyz/angularjs-template-compatible and squashes the following commits: 3474f81c5 [Hsuan Lee] fix: fix editor focus d639a2b13 [Hsuan Lee] fix: fix focus bar 38d0c4659 [Hsuan Lee] chore: update code editor actions 1a28a7a9f [Hsuan Lee] feat: provide Angular.js template migration tool --- .../main/resources/interpreter-setting.json | 11 + zeppelin-web-angular/package-lock.json | 18 +- zeppelin-web-angular/package.json | 3 + .../code-editor/code-editor.component.html | 5 +- .../code-editor/code-editor.component.less | 6 +- .../code-editor/code-editor.component.ts | 10 +- .../paragraph/control/control.component.ts | 117 ++++--- .../notebook/paragraph/paragraph.component.ts | 297 ++++++++++-------- .../paragraph/result/result.component.html | 2 +- .../paragraph/result/result.component.ts | 17 +- .../services/ng-template-adapter.service.ts | 65 ++++ .../ng1-migration.component.html | 54 ++++ .../ng1-migration.component.less | 77 +++++ .../ng1-migration/ng1-migration.component.ts | 174 ++++++++++ .../src/app/share/share.module.ts | 4 +- 15 files changed, 646 insertions(+), 214 deletions(-) create mode 100644 zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts create mode 100644 zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html create mode 100644 zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less create mode 100644 zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts diff --git a/angular/src/main/resources/interpreter-setting.json b/angular/src/main/resources/interpreter-setting.json index 723348d25e9..957295f8322 100644 --- a/angular/src/main/resources/interpreter-setting.json +++ b/angular/src/main/resources/interpreter-setting.json @@ -9,5 +9,16 @@ "editOnDblClick": true, "completionSupport": false } + }, + { + "group": "angular", + "name": "ng", + "className": "org.apache.zeppelin.angular.AngularInterpreter", + "properties": { + }, + "editor": { + "editOnDblClick": true, + "completionSupport": false + } } ] diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index 85ad2a6251f..cd5fb2fd43f 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -2370,6 +2370,12 @@ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, + "@types/parse5": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.2.tgz", + "integrity": "sha512-BOl+6KDs4ItndUWUFchy3aEqGdHhw0BC4Uu+qoDonN/f0rbUnJbm71Ulj8Tt9jLFRaAxPLKvdS1bBLfx1qXR9g==", + "dev": true + }, "@types/q": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", @@ -9967,6 +9973,11 @@ "tslib": "^1.9.0" } }, + "ng1-template-updater": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/ng1-template-updater/-/ng1-template-updater-0.0.4.tgz", + "integrity": "sha512-GgmAV7Zbj8ZLQ/IJGjjSi40bXTHFP/k5fhlxcH0V2fWaya5lu6y07Vh4LKvuUqNbkbKl28XW8Z1fhL5pwHxgsA==" + }, "ngx-build-plus": { "version": "8.1.5", "resolved": "https://registry.npmjs.org/ngx-build-plus/-/ngx-build-plus-8.1.5.tgz", @@ -10695,10 +10706,9 @@ "integrity": "sha1-en7A0esG+lMlx9PgCbhZoJtdSes=" }, "parse5": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz", - "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==", - "optional": true + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" }, "parseqs": { "version": "0.0.5", diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 63b6be17d43..9d9aa934a3f 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -37,6 +37,8 @@ "mathjax": "2.7.5", "monaco-editor": "^0.18.1", "ng-zorro-antd": "^8.4.0", + "ng1-template-updater": "0.0.4", + "parse5": "^5.1.1", "rxjs": "~6.5.3", "systemjs": "^5.0.0", "tslib": "^1.9.0", @@ -56,6 +58,7 @@ "@types/lodash": "^4.14.124", "@types/mathjax": "^0.0.35", "@types/node": "~8.9.4", + "@types/parse5": "^5.0.2", "codelyzer": "^5.0.0", "dotenv": "^8.0.0", "https-proxy-agent": "^2.2.1", diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html index 4d382f2b82f..d543e670d49 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.html @@ -11,6 +11,7 @@ --> + [class.focused]="focus" + [class.dirty]="dirty" + (nzEditorInitialized)="initializedEditor($event)"> diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less index 72a1f689dc8..8f61bd5b93f 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.less @@ -18,7 +18,7 @@ .themeMixin({ - zeppelin-monaco-editor { + zeppelin-code-editor { display: block; border-left: 4px solid @border-color-split; overflow: hidden; @@ -26,6 +26,10 @@ &.dirty { border-left-color: @warning-color; } + + &.focused:not(.dirty) { + border-left-color: @primary-color; + } } }); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index 0711e816542..916afefd9e3 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -76,16 +76,10 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro const editor = this.editor; this.monacoDisposables.push( editor.onDidFocusEditorText(() => { - this.ngZone.runOutsideAngular(() => { - this.editorFocus.emit(); - editor.updateOptions({ renderLineHighlight: 'all' }); - }); + this.editorFocus.emit(); }), editor.onDidBlurEditorText(() => { this.editorBlur.emit(); - this.ngZone.runOutsideAngular(() => { - editor.updateOptions({ renderLineHighlight: 'none' }); - }); }), editor.onDidChangeModelContent(() => { @@ -110,13 +104,11 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro initializedEditor(editor: IEditor) { this.editor = editor as IStandaloneCodeEditor; - this.paragraphControl.updateListOfMenu(monaco); if (this.paragraphControl) { this.paragraphControl.listOfMenu.forEach((item, index) => { this.editor.addAction({ id: item.icon, label: item.label, - keybindings: item.keyBindings, precondition: null, keybindingContext: null, contextMenuGroupId: 'navigation', diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts index 5b959539d92..bda003d8687 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -81,20 +81,66 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: boolean; icon: string; shortCut: string; - keyBindings: number[]; trigger(): void; }> = []; - updateListOfMenu(monaco?) { + updateListOfMenu() { this.listOfMenu = [ + { + label: 'Run', + show: !this.first, + disabled: this.isEntireNoteRunning, + icon: 'play-circle', + trigger: () => this.trigger(this.runParagraph), + shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + }, + { + label: 'Run all above', + show: !this.first, + disabled: this.isEntireNoteRunning, + icon: 'up-square', + trigger: () => this.trigger(this.runAllAbove), + shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + }, + { + label: 'Run all below', + show: !this.last, + disabled: this.isEntireNoteRunning, + icon: 'down-square', + trigger: () => this.trigger(this.runAllBelowAndCurrent), + shortCut: this.isMac ? '⇧+⌘+Enter' : 'Shift+Ctrl+Enter' + }, + { + label: 'Link this paragraph', + show: true, + disabled: false, + icon: 'export', + trigger: () => this.goToSingleParagraph(), + shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W` + }, + { + label: 'Clear output', + show: true, + disabled: this.isEntireNoteRunning, + icon: 'fire', + trigger: () => this.clearParagraphOutput(), + shortCut: this.isMac ? '⌥+⌘+L' : 'Alt+Ctrl+L' + }, + { + label: 'Remove', + show: this.paragraphLength > 1, + disabled: this.isEntireNoteRunning, + icon: 'delete', + trigger: () => this.onRemoveParagraph(), + shortCut: this.isMac ? '⇧+Del (Command)' : 'Shift+Del (Command)' + }, { label: 'Move up', show: !this.first, disabled: this.isEntireNoteRunning, icon: 'up', trigger: () => this.trigger(this.moveUp), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+K`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_K] : [] + shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+K (Command)` }, { label: 'Move down', @@ -102,8 +148,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'down', trigger: () => this.trigger(this.moveDown), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+J`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_J] : [] + shortCut: `${this.isMac ? '⌘' : 'Ctrl'}+J (Command)` }, { label: 'Insert new', @@ -111,26 +156,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'plus', trigger: () => this.trigger(this.insertNew), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+B`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_B] : [] - }, - { - label: 'Run all above', - show: !this.first, - disabled: this.isEntireNoteRunning, - icon: 'up-square', - trigger: () => this.trigger(this.runAllAbove), - shortCut: `Ctrl+Shift+Enter`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : [] - }, - { - label: 'Run all below', - show: !this.last, - disabled: this.isEntireNoteRunning, - icon: 'down-square', - trigger: () => this.trigger(this.runAllBelowAndCurrent), - shortCut: `Ctrl+Shift+Enter`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.Enter] : [] + shortCut: `B (Command)` }, { label: 'Clone paragraph', @@ -138,8 +164,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'copy', trigger: () => this.trigger(this.cloneParagraph), - shortCut: `Ctrl+Shift+C`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Shift | monaco.KeyCode.KEY_C] : [] + shortCut: `C (Command)` }, { label: this.title ? 'Hide Title' : 'Show Title', @@ -147,8 +172,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: false, icon: 'font-colors', trigger: () => this.toggleTitle(), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+T`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_T] : [] + shortCut: `T (Command)` }, { label: this.lineNumbers ? 'Hide line numbers' : 'Show line numbers', @@ -156,8 +180,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: false, icon: 'ordered-list', trigger: () => this.toggleLineNumbers(), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+M`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_M] : [] + shortCut: `L (Command)` }, { label: this.enabled ? 'Disable run' : 'Enable run', @@ -165,35 +188,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { disabled: this.isEntireNoteRunning, icon: 'api', trigger: () => this.toggleEnabled(), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+R`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_R] : [] - }, - { - label: 'Link this paragraph', - show: true, - disabled: false, - icon: 'export', - trigger: () => this.goToSingleParagraph(), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_W] : [] - }, - { - label: 'Clear output', - show: true, - disabled: this.isEntireNoteRunning, - icon: 'fire', - trigger: () => this.clearParagraphOutput(), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+L`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_L] : [] - }, - { - label: 'Remove', - show: this.paragraphLength > 1, - disabled: this.isEntireNoteRunning, - icon: 'delete', - trigger: () => this.onRemoveParagraph(), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+D`, - keyBindings: monaco ? [monaco.KeyMod.WinCtrl | monaco.KeyMod.Alt | monaco.KeyCode.KEY_D] : [] + shortCut: `R (Command)` } ]; } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index 1dde62dae65..f5b61e8006f 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -13,7 +13,8 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, - Component, ElementRef, + Component, + ElementRef, EventEmitter, Input, OnChanges, @@ -25,8 +26,8 @@ import { ViewChild, ViewChildren } from '@angular/core'; -import {merge, Observable, Subject} from 'rxjs'; -import {map, takeUntil} from 'rxjs/operators'; +import { merge, Observable, Subject } from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; import DiffMatchPatch from 'diff-match-patch'; import { isEmpty, isEqual } from 'lodash'; @@ -60,6 +61,7 @@ import { } from '@zeppelin/services'; import { SpellResult } from '@zeppelin/spell/spell-result'; +import { NgTemplateAdapterService } from '@zeppelin/services/ng-template-adapter.service'; import { NzResizeEvent } from 'ng-zorro-antd/resizable'; import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component'; import { NotebookParagraphResultComponent } from './result/result.component'; @@ -71,7 +73,7 @@ type Mode = 'edit' | 'command'; templateUrl: './paragraph.component.html', styleUrls: ['./paragraph.component.less'], host: { - 'tabindex': '-1', + tabindex: '-1', '(focusin)': 'onFocus()' }, changeDetection: ChangeDetectionStrategy.OnPush @@ -210,7 +212,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen this.focusEditor(); } else { this.blurEditor(); - (this.host.nativeElement as HTMLElement).focus(); } } @@ -370,21 +371,22 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen params: p.settings.params }; }); - this.nzModalService.confirm({ - nzTitle: 'Run current and all below?', - nzContent: 'Are you sure to run current and all below?', - nzOnOk: () => { - this.messageService.runAllParagraphs(this.note.id, paragraphs); - } - }).afterClose - .pipe(takeUntil(this.destroy$)) + this.nzModalService + .confirm({ + nzTitle: 'Run current and all below?', + nzContent: 'Are you sure to run current and all below?', + nzOnOk: () => { + this.messageService.runAllParagraphs(this.note.id, paragraphs); + } + }) + .afterClose.pipe(takeUntil(this.destroy$)) .subscribe(() => { this.waitConfirmFromEdit = false; }); // TODO(hsuanxyz): save cursor } - cloneParagraph(position: string = 'below') { + cloneParagraph(position: string = 'below', newText?: string) { let newIndex = -1; for (let i = 0; i < this.note.paragraphs.length; i++) { if (this.note.paragraphs[i].id === this.paragraph.id) { @@ -408,12 +410,30 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen this.messageService.copyParagraph( newIndex, this.paragraph.title, - this.paragraph.text, + newText || this.paragraph.text, config, this.paragraph.settings.params ); } + runParagraphAfter(text: string) { + this.originalText = text; + this.dirtyText = undefined; + + if (this.paragraph.config.editorSetting.editOnDblClick) { + this.paragraph.config.editorHide = true; + this.paragraph.config.tableHide = false; + this.commitParagraph(); + } else if (this.editorSetting.isOutputHidden && !this.paragraph.config.editorSetting.editOnDblClick) { + // %md/%angular repl make output to be hidden by default after running + // so should open output if repl changed from %md/%angular to another + this.paragraph.config.editorHide = false; + this.paragraph.config.tableHide = false; + this.commitParagraph(); + } + this.editorSetting.isOutputHidden = this.paragraph.config.editorSetting.editOnDblClick; + } + runParagraph(paragraphText?: string, propagated: boolean = false) { const text = paragraphText || this.paragraph.text; if (text && !this.isParagraphRunning) { @@ -421,25 +441,34 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen if (this.heliumService.getSpellByMagic(magic)) { this.runParagraphUsingSpell(text, magic, propagated); + this.runParagraphAfter(text); } else { - this.runParagraphUsingBackendInterpreter(text); - } - - this.originalText = text; - this.dirtyText = undefined; - - if (this.paragraph.config.editorSetting.editOnDblClick) { - this.paragraph.config.editorHide = true; - this.paragraph.config.tableHide = false; - this.commitParagraph(); - } else if (this.editorSetting.isOutputHidden && !this.paragraph.config.editorSetting.editOnDblClick) { - // %md/%angular repl make output to be hidden by default after running - // so should open output if repl changed from %md/%angular to another - this.paragraph.config.editorHide = false; - this.paragraph.config.tableHide = false; - this.commitParagraph(); + const check = this.ngTemplateAdapterService.preCheck(text); + if (!check) { + this.runParagraphUsingBackendInterpreter(text); + this.runParagraphAfter(text); + } else { + this.waitConfirmFromEdit = true; + this.nzModalService + .confirm({ + nzTitle: 'Do you want to migrate the Angular.js template?', + nzContent: + 'The Angular.js template has been deprecated, please upgrade to Angular template.' + + ' (more info)', + nzOnOk: () => { + this.switchMode('command'); + this.ngTemplateAdapterService + .openMigrationDialog(check) + .pipe(takeUntil(this.destroy$)) + .subscribe(newText => { + this.cloneParagraph('below', newText); + }); + } + }) + .afterClose.pipe(takeUntil(this.destroy$)) + .subscribe(() => (this.waitConfirmFromEdit = false)); + } } - this.editorSetting.isOutputHidden = this.paragraph.config.editorSetting.editOnDblClick; } } @@ -693,125 +722,131 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen private cdr: ChangeDetectorRef, private ngZService: NgZService, private shortcutService: ShortcutService, - private host: ElementRef + private host: ElementRef, + private ngTemplateAdapterService: NgTemplateAdapterService ) { super(messageService); } ngOnInit() { const shortcutService = this.shortcutService.forkByElement(this.host.nativeElement); - const observables: Array> = []; + const observables: Array< + Observable<{ + action: ParagraphActions; + event: KeyboardEvent; + }> + > = []; Object.entries(ShortcutsMap).forEach(([action, keys]) => { const keysArr: string[] = Array.isArray(keys) ? keys : [keys]; keysArr.forEach(key => { observables.push( - shortcutService.bindShortcut({ - keybindings: key - }).pipe( - takeUntil(this.destroy$), - map(({event}) => { - return { - event, - action: action as ParagraphActions - } - })) + shortcutService + .bindShortcut({ + keybindings: key + }) + .pipe( + takeUntil(this.destroy$), + map(({ event }) => { + return { + event, + action: action as ParagraphActions + }; + }) + ) ); }); }); merge<{ - action: ParagraphActions, - event: KeyboardEvent + action: ParagraphActions; + event: KeyboardEvent; }>(...observables) .pipe(takeUntil(this.destroy$)) - .subscribe(({action, event}) => { - if (this.mode === 'command') { + .subscribe(({ action, event }) => { + if (this.mode === 'command') { + switch (action) { + case ParagraphActions.InsertAbove: + this.insertParagraph('above'); + break; + case ParagraphActions.InsertBelow: + this.insertParagraph('below'); + break; + case ParagraphActions.SwitchEditorShow: + this.setEditorHide(!this.paragraph.config.editorHide); + this.commitParagraph(); + break; + case ParagraphActions.SwitchOutputShow: + this.setTableHide(!this.paragraph.config.tableHide); + this.commitParagraph(); + break; + case ParagraphActions.SwitchTitleShow: + this.paragraph.config.title = !this.paragraph.config.title; + this.commitParagraph(); + break; + case ParagraphActions.SwitchLineNumber: + this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers; + this.commitParagraph(); + break; + case ParagraphActions.MoveToUp: + this.moveUpParagraph(); + break; + case ParagraphActions.MoveToDown: + this.moveDownParagraph(); + break; + case ParagraphActions.SwitchEnable: + this.paragraph.config.enabled = !this.paragraph.config.enabled; + this.commitParagraph(); + break; + case ParagraphActions.ReduceWidth: + this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.IncreaseWidth: + this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1); + this.cdr.markForCheck(); + this.changeColWidth(true); + break; + case ParagraphActions.Delete: + this.removeParagraph(); + break; + case ParagraphActions.SelectAbove: + event.preventDefault(); + this.selectAtIndex.emit(this.index - 1); + break; + case ParagraphActions.SelectBelow: + event.preventDefault(); + this.selectAtIndex.emit(this.index + 1); + break; + default: + break; + } + } switch (action) { - case ParagraphActions.InsertAbove: - this.insertParagraph('above'); - break; - case ParagraphActions.InsertBelow: - this.insertParagraph('below'); - break; - case ParagraphActions.SwitchEditorShow: - this.setEditorHide(!this.paragraph.config.editorHide); - this.commitParagraph(); - break; - case ParagraphActions.SwitchOutputShow: - this.setTableHide(!this.paragraph.config.tableHide); - this.commitParagraph(); - break; - case ParagraphActions.SwitchTitleShow: - this.paragraph.config.title = !this.paragraph.config.title; - this.commitParagraph(); - break; - case ParagraphActions.SwitchLineNumber: - this.paragraph.config.lineNumbers = !this.paragraph.config.lineNumbers; - this.commitParagraph(); - break; - case ParagraphActions.MoveToUp: - this.moveUpParagraph(); - break; - case ParagraphActions.MoveToDown: - this.moveDownParagraph(); - break; - case ParagraphActions.SwitchEnable: - this.paragraph.config.enabled = !this.paragraph.config.enabled; - this.commitParagraph(); - break; - case ParagraphActions.ReduceWidth: - this.paragraph.config.colWidth = Math.max(1, this.paragraph.config.colWidth - 1); - this.cdr.markForCheck(); - this.changeColWidth(true); - break; - case ParagraphActions.IncreaseWidth: - this.paragraph.config.colWidth = Math.min(12, this.paragraph.config.colWidth + 1); - this.cdr.markForCheck(); - this.changeColWidth(true); - break; - case ParagraphActions.Delete: - this.removeParagraph(); + case ParagraphActions.EditMode: + if (this.mode === 'command') { + event.preventDefault(); + } + if (!this.paragraph.config.editorHide) { + this.switchMode('edit'); + } break; - case ParagraphActions.SelectAbove: + case ParagraphActions.Run: event.preventDefault(); - this.selectAtIndex.emit(this.index - 1); + this.runParagraph(); + break; + case ParagraphActions.RunBelow: + this.waitConfirmFromEdit = true; + this.runAllBelowAndCurrent(); break; - case ParagraphActions.SelectBelow: + case ParagraphActions.Cancel: event.preventDefault(); - this.selectAtIndex.emit(this.index + 1); + this.cancelParagraph(); break; default: break; } - } - switch (action) { - case ParagraphActions.EditMode: - if (this.mode === 'command') { - event.preventDefault(); - } - if (!this.paragraph.config.editorHide) { - this.switchMode('edit'); - } - break; - case ParagraphActions.Run: - event.preventDefault(); - this.runParagraph(); - break; - case ParagraphActions.RunBelow: - this.waitConfirmFromEdit = true; - this.runAllBelowAndCurrent(); - break; - case ParagraphActions.Cancel: - event.preventDefault(); - this.cancelParagraph(); - break; - default: - break; - } - }); + }); this.setResults(); this.originalText = this.paragraph.text; @@ -843,12 +878,16 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen ngOnChanges(changes: SimpleChanges): void { const { index, select } = changes; - if (index && index.currentValue !== index.previousValue && this.select - || select && select.currentValue === true && select.previousValue !== true) { + if ( + (index && index.currentValue !== index.previousValue && this.select) || + (select && select.currentValue === true && select.previousValue !== true) + ) { if (this.host.nativeElement) { setTimeout(() => { - (this.host.nativeElement as HTMLElement).focus(); - }) + if (this.mode === 'command') { + (this.host.nativeElement as HTMLElement).focus(); + } + }); } } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html index 028c3e50089..fe34a372d69 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html @@ -65,7 +65,7 @@ zeppelinRunScripts [scriptsContent]="innerHTML" [innerHTML]="innerHTML">
-
+
{{plainText}}
img
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts index 903f72bccc5..742a9fb29a8 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts @@ -16,7 +16,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - ElementRef, EventEmitter, Injector, Input, @@ -81,6 +80,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, plainText: string | SafeHtml = ''; imgData: string | SafeUrl = ''; tableData = new TableData(); + frontEndError: string; // tslint:disable-next-line:no-any visualizations: any[] = [ { @@ -236,11 +236,16 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, } renderAngular(): void { - this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => { - this.angularComponent = data; - // this.angularComponent.moduleFactory - this.cdr.markForCheck(); - }); + try { + this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => { + this.angularComponent = data; + // this.angularComponent.moduleFactory + this.cdr.markForCheck(); + }); + } catch (e) { + this.frontEndError = e.message; + console.log(e); + } } renderText(): void { diff --git a/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts new file mode 100644 index 00000000000..651b709019c --- /dev/null +++ b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts @@ -0,0 +1,65 @@ +/* + * 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 { Injectable } from '@angular/core'; +import { Ng1MigrationComponent } from '@zeppelin/share/ng1-migration/ng1-migration.component'; +import { NzModalService } from 'ng-zorro-antd'; +import { Observable } from 'rxjs'; + +export interface NgTemplateCheckResult { + index: number; + match: string; + magic: string; + template: string; + origin: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class NgTemplateAdapterService { + constructor(private nzModalService: NzModalService) {} + preCheck(origin: string): NgTemplateCheckResult | null { + const regexp = /(%angular)([\s\S]*<[\s\S]*>)/im; + const math = regexp.exec(origin); + if (math) { + const index = math.index; + const [output, magic, template] = math; + return { + index, + magic, + template, + origin, + match: output + }; + } + return null; + } + + openMigrationDialog(check: NgTemplateCheckResult): Observable { + const modalRef = this.nzModalService.create({ + nzTitle: 'Angular.js Templates Migration Tool', + nzContent: Ng1MigrationComponent, + nzComponentParams: check, + nzFooter: null, + nzWidth: '980px', + nzStyle: { + top: '45px' + }, + nzBodyStyle: { + padding: '0' + } + }); + + return modalRef.afterClose; + } +} diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html new file mode 100644 index 00000000000..34d948ab9f7 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.html @@ -0,0 +1,54 @@ +
+ + +
+
+ +
+ + + + + {{errorCount}} + + + + {{messageDetails.length - errorCount}} + + +
+ +
+ + + ({{(item.pos.line + 1) + ',' + (item.pos.character + 1)}}) + {{item.message}} + more +
+
+ +
+ + +
diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less new file mode 100644 index 00000000000..cb1fdc26721 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.less @@ -0,0 +1,77 @@ +:host { + height: 70vh; + display: flex; + + .code-editor { + flex: auto; + } + + .messages { + overflow: auto; + position: relative; + width: 240px; + border-left: 1px solid #e8e8e8; + + i { + &.error { + color: red; + } + &.close { + color: #1f8ffb; + } + } + + .fix-bar { + padding-right: 16px; + display: flex; + font-size: 12px; + border-bottom: 1px solid #e8e8e8; + height: 25px; + line-height: 25px; + .fix-btn { + flex: 0; + font-size: 12px; + } + .log-counts { + text-align: right; + flex: 1 auto; + } + } + + + .message { + font-family: Consolas, Verdana; + color: #1e1e1e; + padding: 8px 16px 8px 5px; + transition: background-color 0.3s; + word-break: break-all; + line-height: 17px; + cursor: pointer; + font-size: 12px; + .position { + color: #5d5d5d; + } + &:hover { + background-color: #ffb86c; + } + } + } +} + + +::ng-deep { + .monaco-editor { + .scroll-decoration { + box-shadow: none; + } + .decoration-link { + text-decoration-color: red; + text-decoration-line: underline; + text-decoration-style: wavy; + text-decoration-skip-ink: none; + } + .warn-content { + background: rgba(182, 182, 182, .3); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts new file mode 100644 index 00000000000..340330e92ff --- /dev/null +++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts @@ -0,0 +1,174 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core'; +import { editor, IDisposable, Range } from 'monaco-editor'; +import { NzModalRef } from 'ng-zorro-antd'; +import { + defaultTemplateUpdaterRules, + LogLevel, + Message, + MessageDetail, + TemplateUpdater, + ValueChangeRule +} from 'ng1-template-updater'; +import { combineLatest, Subject } from 'rxjs'; +import IEditor = editor.IEditor; +import ITextModel = editor.ITextModel; +import IStandaloneCodeEditor = editor.IStandaloneCodeEditor; + +const zeppelinFunctionChangeRule: ValueChangeRule = (expression: string, start?: number) => { + let value = expression; + const messages: Message[] = []; + const funChanges = [ + { + regexp: /z\.angularBind/gm, + replace: 'z.set' + }, + { + regexp: /z\.angularUnbind/gm, + replace: 'z.unset' + }, + { + regexp: /z\.runParagraph/gm, + replace: 'z.run' + } + ]; + + funChanges.forEach(change => { + let match = change.regexp.exec(value); + while (match !== null) { + messages.push({ + position: start + match.index, + message: `${match[0]} has been deprecated, using ${change.replace} instead`, + length: match[0].length, + // url: 'https://angular.io/guide/ajs-quick-reference', + level: LogLevel.Info + }); + match = change.regexp.exec(value); + } + value = value.replace(change.regexp, change.replace); + }); + + return { + messages, + value + }; +}; + +@Component({ + selector: 'zeppelin-ng1-migration', + templateUrl: './ng1-migration.component.html', + styleUrls: ['./ng1-migration.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class Ng1MigrationComponent implements OnDestroy { + @Input() origin: string; + @Input() index: number; + @Input() match: string; + @Input() template: string; + + messageDetails: MessageDetail[] = []; + templateUpdater: TemplateUpdater; + errorCount = 0; + decorations: string[] = []; + timeoutId = -1; + editor: IStandaloneCodeEditor; + editorModel: ITextModel; + editorInit$ = new Subject(); + editorChangeDisposable: IDisposable; + + constructor(private nzModalRef: NzModalRef, private cdr: ChangeDetectorRef) { + const updateRules = { + ...defaultTemplateUpdaterRules, + valueChangeRules: [...defaultTemplateUpdaterRules.valueChangeRules, zeppelinFunctionChangeRule] + }; + this.templateUpdater = new TemplateUpdater(updateRules); + combineLatest([this.nzModalRef.afterOpen, this.editorInit$]).subscribe(() => { + if (this.editor) { + this.editorModel = this.editor.getModel() as ITextModel; + this.editor.setValue(this.template); + this.editor.layout(); + this.bindEditorEvents(); + this.check(); + setTimeout(() => { + this.editor.focus(); + }, 150); + } + }); + } + + onEditorInit(_editor: IEditor) { + this.editorInit$.next(); + this.editorInit$.complete(); + this.editor = _editor as IStandaloneCodeEditor; + } + + bindEditorEvents() { + if (this.editorModel) { + this.editorChangeDisposable = this.editorModel.onDidChangeContent(() => { + clearTimeout(this.timeoutId); + this.timeoutId = setTimeout(() => { + this.check(); + }, 300); + }); + } + } + + scrollToLine(failure: MessageDetail) { + const line = failure.pos.line + 1; + const character = failure.pos.character + 1; + const range = new Range(line, character, line, character + failure.length); + this.editor.revealRangeAtTop(range); + this.editor.setSelection(range); + this.editor.focus(); + } + + check() { + const code = this.editor.getValue(); + const { messages } = this.templateUpdater.parse(code); + this.messageDetails = [...messages]; + this.errorCount = messages.filter(f => f.level === LogLevel.Error).length; + this.decorations = this.editor.deltaDecorations( + this.decorations, + messages.map(failure => { + const line = failure.pos.line + 1; + const character = failure.pos.character + 1; + return { + range: new Range(line, character, line, character + failure.length), + options: { + className: failure.level === LogLevel.Error ? '' : 'warn-content', + inlineClassName: failure.level === LogLevel.Error ? 'decoration-link' : '', + stickiness: 1, + hoverMessage: { + value: failure.message + (failure.url ? ` [more](${failure.url})` : '') + } + } + }; + }) + ); + this.cdr.markForCheck(); + } + + fix() { + const code = this.editor.getValue(); + const { template } = this.templateUpdater.parse(code); + this.editor.setValue(template); + } + + updateAndCopy() { + const code = this.editor.getValue(); + const newTemplate = this.origin.replace(this.match, `%ng\n${code}`); + this.nzModalRef.close(newTemplate); + } + + cancel() { + this.nzModalRef.destroy(); + } + + ngOnDestroy(): void { + if (this.editorChangeDisposable) { + this.editorChangeDisposable.dispose(); + } + if (this.editorModel) { + this.editorModel.dispose(); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts index ed5d191736a..fcb03751092 100644 --- a/zeppelin-web-angular/src/app/share/share.module.ts +++ b/zeppelin-web-angular/src/app/share/share.module.ts @@ -52,6 +52,7 @@ import { PageHeaderComponent } from '@zeppelin/share/page-header/page-header.com import { HumanizeBytesPipe } from '@zeppelin/share/pipes'; import { RunScriptsDirective } from '@zeppelin/share/run-scripts/run-scripts.directive'; import { SpinComponent } from '@zeppelin/share/spin/spin.component'; +import { Ng1MigrationComponent } from './ng1-migration/ng1-migration.component'; import { ResizeHandleComponent } from './resize-handle'; const MODAL_LIST = [ @@ -59,7 +60,8 @@ const MODAL_LIST = [ NoteImportComponent, NoteCreateComponent, NoteRenameComponent, - FolderRenameComponent + FolderRenameComponent, + Ng1MigrationComponent ]; const EXPORT_LIST = [HeaderComponent, NodeListComponent, PageHeaderComponent, SpinComponent, ResizeHandleComponent]; const PIPES = [HumanizeBytesPipe]; From 66f4dd1489ca738bdee7757ff64a6e63b348589d Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Fri, 29 Nov 2019 17:16:34 +0800 Subject: [PATCH 10/32] [ZEPPELIN-4403] Support publishable for paragraph ### What is this PR for? A few sentences describing the overall goals of the pull request's commits. First time? Check out the contributing guide - https://zeppelin.apache.org/contribution/contributions.html ### What type of PR is it? [Feature] ### Todos * ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4403 ### How should this be tested? * First time? Setup Travis CI as described on https://zeppelin.apache.org/contribution/contributions.html#continuous-integration * Strongly recommended: add automated unit tests for any new or changed behavior * Outline any manual steps to test the PR here. ### Screenshots (if appropriate) ![publish](https://user-images.githubusercontent.com/22736418/69940879-4770d300-151e-11ea-9ed1-2925ce825e58.gif) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3530 from hsuanxyz/paragraph-publishable and squashes the following commits: a9b974c1d [Hsuan Lee] feat: support paragraph publishable --- .../src/app/core/paragraph-base/index.ts | 13 + .../app/core/paragraph-base/paragraph-base.ts | 315 ++++++++++++++++++ .../src/app/core/paragraph-base/public-api.ts | 14 + .../src/app/core/paragraph-base/published.ts | 17 + .../src/app/core/public-api.ts | 1 + .../notebook/notebook-routing.module.ts | 4 - .../workspace/notebook/notebook.component.ts | 13 +- .../workspace/notebook/notebook.module.ts | 14 +- .../code-editor/code-editor.component.ts | 14 - .../paragraph/control/control.component.ts | 17 +- .../paragraph/paragraph.component.html | 1 + .../notebook/paragraph/paragraph.component.ts | 305 +---------------- .../paragraph/paragraph.component.html | 15 + .../paragraph/paragraph.component.less | 0 .../paragraph/paragraph.component.ts | 88 +++++ .../published/published-ruoting.module.ts | 28 ++ .../workspace/published/published.module.ts | 11 + .../dynamic-forms.component.html | 0 .../dynamic-forms.component.less | 0 .../dynamic-forms/dynamic-forms.component.ts | 0 .../src/app/pages/workspace/share/index.ts | 13 + .../app/pages/workspace/share/public-api.ts | 13 + .../result/result.component.html | 6 +- .../result/result.component.less | 0 .../result/result.component.ts | 4 + .../app/pages/workspace/share/share.module.ts | 56 ++++ .../workspace/workspace-routing.module.ts | 4 + .../pages/workspace/workspace.component.html | 4 +- .../pages/workspace/workspace.component.ts | 11 +- .../src/app/services/shortcut.service.ts | 37 +- 30 files changed, 665 insertions(+), 353 deletions(-) create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/index.ts create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts create mode 100644 zeppelin-web-angular/src/app/core/paragraph-base/published.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts rename zeppelin-web-angular/src/app/pages/workspace/{notebook/paragraph => share}/dynamic-forms/dynamic-forms.component.html (100%) rename zeppelin-web-angular/src/app/pages/workspace/{notebook/paragraph => share}/dynamic-forms/dynamic-forms.component.less (100%) rename zeppelin-web-angular/src/app/pages/workspace/{notebook/paragraph => share}/dynamic-forms/dynamic-forms.component.ts (100%) create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/index.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts rename zeppelin-web-angular/src/app/pages/workspace/{notebook/paragraph => share}/result/result.component.html (95%) rename zeppelin-web-angular/src/app/pages/workspace/{notebook/paragraph => share}/result/result.component.less (100%) rename zeppelin-web-angular/src/app/pages/workspace/{notebook/paragraph => share}/result/result.component.ts (99%) create mode 100644 zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/index.ts b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts new file mode 100644 index 00000000000..f8f9a1be7b2 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts @@ -0,0 +1,315 @@ +/* + * 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 { ChangeDetectorRef, QueryList } from '@angular/core'; + +import { + AngularObjectRemove, + AngularObjectUpdate, + GraphConfig, + MessageReceiveDataTypeMap, + OP, + ParagraphConfig, + ParagraphEditorSetting, + ParagraphItem, + ParagraphIResultsMsgItem +} from '@zeppelin/sdk'; + +import { MessageService } from '@zeppelin/services/message.service'; +import { NgZService } from '@zeppelin/services/ng-z.service'; +import { NoteStatusService, ParagraphStatus } from '@zeppelin/services/note-status.service'; + +import DiffMatchPatch from 'diff-match-patch'; +import { isEmpty, isEqual } from 'lodash'; + +import { NotebookParagraphResultComponent } from '@zeppelin/pages/workspace/share/result/result.component'; +import { MessageListener, MessageListenersManager } from '../message-listener/message-listener'; + +export abstract class ParagraphBase extends MessageListenersManager { + paragraph: ParagraphItem; + dirtyText: string; + originalText: string; + isEntireNoteRunning = false; + revisionView = false; + diffMatchPatch = new DiffMatchPatch(); + isParagraphRunning = false; + results = []; + configs = {}; + progress = 0; + colWidthOption = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; + editorSetting: ParagraphEditorSetting = {}; + + notebookParagraphResultComponents: QueryList; + + constructor( + public messageService: MessageService, + protected noteStatusService: NoteStatusService, + protected ngZService: NgZService, + protected cdr: ChangeDetectorRef + ) { + super(messageService); + } + + abstract changeColWidth(needCommit: boolean, updateResult?: boolean): void; + + @MessageListener(OP.PROGRESS) + onProgress(data: MessageReceiveDataTypeMap[OP.PROGRESS]) { + if (data.id === this.paragraph.id) { + this.progress = data.progress; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.NOTE_RUNNING_STATUS) + noteRunningStatusChange(data: MessageReceiveDataTypeMap[OP.NOTE_RUNNING_STATUS]) { + this.isEntireNoteRunning = data.status; + this.cdr.markForCheck(); + } + + @MessageListener(OP.PARAS_INFO) + updateParaInfos(data: MessageReceiveDataTypeMap[OP.PARAS_INFO]) { + if (this.paragraph.id === data.id) { + this.paragraph.runtimeInfos = data.infos; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.EDITOR_SETTING) + getEditorSetting(data: MessageReceiveDataTypeMap[OP.EDITOR_SETTING]) { + if (this.paragraph.id === data.paragraphId) { + this.paragraph.config.editorSetting = { ...this.paragraph.config.editorSetting, ...data.editor }; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.PARAGRAPH) + paragraphData(data: MessageReceiveDataTypeMap[OP.PARAGRAPH]) { + const oldPara = this.paragraph; + const newPara = data.paragraph; + if (this.isUpdateRequired(oldPara, newPara)) { + this.updateParagraph(oldPara, newPara, () => { + if (newPara.results && newPara.results.msg) { + // tslint:disable-next-line:no-for-in-array + for (const i in newPara.results.msg) { + if (newPara.results.msg[i]) { + const newResult = newPara.results.msg ? newPara.results.msg[i] : new ParagraphIResultsMsgItem(); + const oldResult = + oldPara.results && oldPara.results.msg ? oldPara.results.msg[i] : new ParagraphIResultsMsgItem(); + const newConfig = newPara.config.results ? newPara.config.results[i] : { graph: new GraphConfig() }; + const oldConfig = oldPara.config.results ? oldPara.config.results[i] : { graph: new GraphConfig() }; + if (!isEqual(newResult, oldResult) || !isEqual(newConfig, oldConfig)) { + const resultComponent = this.notebookParagraphResultComponents.toArray()[i]; + if (resultComponent) { + resultComponent.updateResult(newConfig, newResult); + } + } + } + } + } + this.cdr.markForCheck(); + }); + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.PATCH_PARAGRAPH) + patchParagraph(data: MessageReceiveDataTypeMap[OP.PATCH_PARAGRAPH]) { + if (data.paragraphId === this.paragraph.id) { + let patch = data.patch; + patch = this.diffMatchPatch.patch_fromText(patch); + if (!this.paragraph.text) { + this.paragraph.text = ''; + } + this.paragraph.text = this.diffMatchPatch.patch_apply(patch, this.paragraph.text)[0]; + this.originalText = this.paragraph.text; + this.cdr.markForCheck(); + } + } + + @MessageListener(OP.ANGULAR_OBJECT_UPDATE) + angularObjectUpdate(data: AngularObjectUpdate) { + if (data.paragraphId === this.paragraph.id) { + const { name, object } = data.angularObject; + this.ngZService.setContextValue(name, object, data.paragraphId, false); + } + } + + @MessageListener(OP.ANGULAR_OBJECT_REMOVE) + angularObjectRemove(data: AngularObjectRemove) { + if (data.paragraphId === this.paragraph.id) { + this.ngZService.unsetContextValue(data.name, data.paragraphId, false); + } + } + + updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) { + // 1. can't update on revision view + if (!this.revisionView) { + // 2. get status, refreshed + const statusChanged = newPara.status !== oldPara.status; + const resultRefreshed = + newPara.dateFinished !== oldPara.dateFinished || + isEmpty(newPara.results) !== isEmpty(oldPara.results) || + newPara.status === ParagraphStatus.ERROR || + (newPara.status === ParagraphStatus.FINISHED && statusChanged); + + // 3. update texts managed by paragraph + this.updateAllScopeTexts(oldPara, newPara); + // 4. execute callback to update result + updateCallback(); + + // 5. update remaining paragraph objects + this.updateParagraphObjectWhenUpdated(newPara); + + // 6. handle scroll down by key properly if new paragraph is added + if (statusChanged || resultRefreshed) { + // when last paragraph runs, zeppelin automatically appends new paragraph. + // this broadcast will focus to the newly inserted paragraph + // TODO(hsuanxyz) + } + this.cdr.markForCheck(); + } + } + + isUpdateRequired(oldPara: ParagraphItem, newPara: ParagraphItem): boolean { + return ( + newPara.id === oldPara.id && + (newPara.dateCreated !== oldPara.dateCreated || + newPara.text !== oldPara.text || + newPara.dateFinished !== oldPara.dateFinished || + newPara.dateStarted !== oldPara.dateStarted || + newPara.dateUpdated !== oldPara.dateUpdated || + newPara.status !== oldPara.status || + newPara.jobName !== oldPara.jobName || + newPara.title !== oldPara.title || + isEmpty(newPara.results) !== isEmpty(oldPara.results) || + newPara.errorMessage !== oldPara.errorMessage || + !isEqual(newPara.settings, oldPara.settings) || + !isEqual(newPara.config, oldPara.config) || + !isEqual(newPara.runtimeInfos, oldPara.runtimeInfos)) + ); + } + + updateAllScopeTexts(oldPara: ParagraphItem, newPara: ParagraphItem) { + if (oldPara.text !== newPara.text) { + if (this.dirtyText) { + // check if editor has local update + if (this.dirtyText === newPara.text) { + // when local update is the same from remote, clear local update + this.paragraph.text = newPara.text; + this.dirtyText = undefined; + this.originalText = newPara.text; + } else { + // if there're local update, keep it. + this.paragraph.text = newPara.text; + } + } else { + this.paragraph.text = newPara.text; + this.originalText = newPara.text; + } + } + this.cdr.markForCheck(); + } + + updateParagraphObjectWhenUpdated(newPara: ParagraphItem) { + if (this.paragraph.config.colWidth !== newPara.config.colWidth) { + this.changeColWidth(false); + } + this.paragraph.aborted = newPara.aborted; + this.paragraph.user = newPara.user; + this.paragraph.dateUpdated = newPara.dateUpdated; + this.paragraph.dateCreated = newPara.dateCreated; + this.paragraph.dateFinished = newPara.dateFinished; + this.paragraph.dateStarted = newPara.dateStarted; + this.paragraph.errorMessage = newPara.errorMessage; + this.paragraph.jobName = newPara.jobName; + this.paragraph.title = newPara.title; + this.paragraph.lineNumbers = newPara.lineNumbers; + this.paragraph.status = newPara.status; + this.paragraph.fontSize = newPara.fontSize; + if (newPara.status !== ParagraphStatus.RUNNING) { + this.paragraph.results = newPara.results; + } + this.paragraph.settings = newPara.settings; + this.paragraph.runtimeInfos = newPara.runtimeInfos; + this.isParagraphRunning = this.noteStatusService.isParagraphRunning(newPara); + this.paragraph.config = newPara.config; + this.initializeDefault(this.paragraph.config); + this.setResults(); + this.cdr.markForCheck(); + } + + setResults() { + if (this.paragraph.results) { + this.results = this.paragraph.results.msg; + this.configs = this.paragraph.config.results; + } + if (!this.paragraph.config) { + this.paragraph.config = {}; + } + } + + initializeDefault(config: ParagraphConfig) { + const forms = this.paragraph.settings.forms; + + if (!config.colWidth) { + config.colWidth = 12; + } + + if (!config.fontSize) { + config.fontSize = 9; + } + + if (config.enabled === undefined) { + config.enabled = true; + } + + for (const idx in forms) { + if (forms[idx]) { + if (forms[idx].options) { + if (config.runOnSelectionChange === undefined) { + config.runOnSelectionChange = true; + } + } + } + } + + if (!config.results) { + config.results = {}; + } + + if (!config.editorSetting) { + config.editorSetting = {}; + } else if (config.editorSetting.editOnDblClick) { + this.editorSetting.isOutputHidden = config.editorSetting.editOnDblClick; + } + } + + runParagraphUsingSpell(paragraphText: string, magic: string, propagated: boolean) { + // TODO(hsuanxyz) + } + + runParagraphUsingBackendInterpreter(paragraphText: string) { + this.messageService.runParagraph( + this.paragraph.id, + this.paragraph.title, + paragraphText, + this.paragraph.config, + this.paragraph.settings.params + ); + } + + cancelParagraph() { + if (!this.isEntireNoteRunning) { + this.messageService.cancelParagraph(this.paragraph.id); + } + } +} diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts new file mode 100644 index 00000000000..a6ba53216ed --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts @@ -0,0 +1,14 @@ +/* + * 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. + */ + +export * from './paragraph-base'; +export * from './published'; diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/published.ts b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts new file mode 100644 index 00000000000..0f415779679 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/paragraph-base/published.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export const publishedSymbol = Symbol('published'); + +export interface Published { + readonly [publishedSymbol]: true; +} diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/public-api.ts index c5141035cc3..3bcd355ab02 100644 --- a/zeppelin-web-angular/src/app/core/public-api.ts +++ b/zeppelin-web-angular/src/app/core/public-api.ts @@ -13,3 +13,4 @@ export * from './message-listener'; export * from './destroy-hook'; export * from './copy-text'; +export * from './paragraph-base'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts index 6c177b6ba80..321b788e74f 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook-routing.module.ts @@ -20,10 +20,6 @@ const routes: Routes = [ path: ':noteId', component: NotebookComponent }, - { - path: ':noteId/paragraph/:paragraphId', - component: NotebookComponent - }, { path: ':noteId/revision/:revisionId', component: NotebookComponent diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index 97479a70938..e0c17a168fb 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -21,7 +21,7 @@ import { } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { isNil } from 'lodash'; -import { Subject} from 'rxjs'; +import { Subject } from 'rxjs'; import { distinctUntilKeyChanged, takeUntil } from 'rxjs/operators'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; @@ -29,6 +29,7 @@ import { Permissions } from '@zeppelin/interfaces'; import { InterpreterBindingItem, MessageReceiveDataTypeMap, Note, OP, RevisionListItem } from '@zeppelin/sdk'; import { MessageService, + NgZService, NoteStatusService, NoteVarShareService, SecurityService, @@ -66,6 +67,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit if (isNil(note)) { this.router.navigate(['/']).then(); } else { + this.removeParagraphFromNgZ(); this.note = note; const { paragraphId } = this.activatedRoute.snapshot.params; if (paragraphId) { @@ -289,6 +291,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit private ticketService: TicketService, private securityService: SecurityService, private router: Router, + protected ngZService: NgZService ) { super(messageService); } @@ -317,6 +320,14 @@ export class NotebookComponent extends MessageListenersManager implements OnInit this.revisionView = !!this.activatedRoute.snapshot.params.revisionId; } + removeParagraphFromNgZ(): void { + if (this.note && Array.isArray(this.note.paragraphs)) { + this.note.paragraphs.forEach(p => { + this.ngZService.removeParagraph(p.id); + }); + } + } + ngOnDestroy(): void { super.ngOnDestroy(); this.killSaveTimer(); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts index ccdd4de9dfd..0258bbe8601 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts @@ -18,7 +18,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NzButtonModule, - NzCheckboxModule, NzDividerModule, NzDropDownModule, NzFormModule, @@ -35,23 +34,20 @@ import { NzToolTipModule } from 'ng-zorro-antd'; import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor'; -import { NzResizableModule } from 'ng-zorro-antd/resizable'; import { ShareModule } from '@zeppelin/share'; -import { VisualizationModule } from 'src/app/visualizations/visualization.module'; import { NotebookAddParagraphComponent } from './add-paragraph/add-paragraph.component'; import { NotebookInterpreterBindingComponent } from './interpreter-binding/interpreter-binding.component'; import { NotebookParagraphCodeEditorComponent } from './paragraph/code-editor/code-editor.component'; import { NotebookParagraphControlComponent } from './paragraph/control/control.component'; -import { NotebookParagraphDynamicFormsComponent } from './paragraph/dynamic-forms/dynamic-forms.component'; import { NotebookParagraphFooterComponent } from './paragraph/footer/footer.component'; import { NotebookParagraphComponent } from './paragraph/paragraph.component'; import { NotebookParagraphProgressComponent } from './paragraph/progress/progress.component'; -import { NotebookParagraphResultComponent } from './paragraph/result/result.component'; import { NotebookPermissionsComponent } from './permissions/permissions.component'; import { NotebookRevisionsComparatorComponent } from './revisions-comparator/revisions-comparator.component'; +import { WorkspaceShareModule } from '../../workspace/share/share.module'; import { NotebookActionBarComponent } from './action-bar/action-bar.component'; import { NotebookRoutingModule } from './notebook-routing.module'; import { NotebookComponent } from './notebook.component'; @@ -67,18 +63,16 @@ import { NotebookShareModule } from './share/share.module'; NotebookParagraphComponent, NotebookAddParagraphComponent, NotebookParagraphCodeEditorComponent, - NotebookParagraphResultComponent, NotebookParagraphProgressComponent, NotebookParagraphFooterComponent, - NotebookParagraphControlComponent, - NotebookParagraphDynamicFormsComponent + NotebookParagraphControlComponent ], imports: [ CommonModule, PortalModule, + WorkspaceShareModule, NotebookRoutingModule, ShareModule, - VisualizationModule, NotebookShareModule, NzButtonModule, NzIconModule, @@ -92,14 +86,12 @@ import { NotebookShareModule } from './share/share.module'; FormsModule, ReactiveFormsModule, NzDividerModule, - NzCheckboxModule, NzProgressModule, NzSwitchModule, NzSelectModule, NzGridModule, NzRadioModule, DragDropModule, - NzResizableModule, NzCodeEditorModule ] }) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index 916afefd9e3..8cf4bd798b8 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -104,20 +104,6 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro initializedEditor(editor: IEditor) { this.editor = editor as IStandaloneCodeEditor; - if (this.paragraphControl) { - this.paragraphControl.listOfMenu.forEach((item, index) => { - this.editor.addAction({ - id: item.icon, - label: item.label, - precondition: null, - keybindingContext: null, - contextMenuGroupId: 'navigation', - contextMenuOrder: index, - run: () => item.trigger() - }); - }); - } - this.editor.addCommand( monaco.KeyCode.Escape, () => { diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts index bda003d8687..eacf2da709a 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -72,6 +72,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { @Output() readonly runAllBelowAndCurrent = new EventEmitter(); @Output() readonly cloneParagraph = new EventEmitter(); @Output() readonly removeParagraph = new EventEmitter(); + @Output() readonly openSingleParagraph = new EventEmitter(); fontSizeOption = [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; dropdownVisible = false; isMac = navigator.appVersion.indexOf('Mac') !== -1; @@ -115,8 +116,10 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { show: true, disabled: false, icon: 'export', - trigger: () => this.goToSingleParagraph(), - shortCut: `Ctrl+${this.isMac ? 'Option' : 'Alt'}+W` + trigger: () => { + this.openSingleParagraph.emit(this.pid); + }, + shortCut: this.isMac ? '⌥+⌘+T' : 'Alt+Ctrl+T' }, { label: 'Clear output', @@ -225,13 +228,6 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { } } - goToSingleParagraph() { - // TODO(hsuanxyz) asIframe - const { noteId } = this.activatedRoute.snapshot.params; - const redirectToUrl = `${location.protocol}//${location.host}${location.pathname}#/notebook/${noteId}/paragraph/${this.pid}`; - window.open(redirectToUrl); - } - changeColWidth(colWidth: number) { this.colWidth = +colWidth; this.colWidthChange.emit(this.colWidth); @@ -269,8 +265,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { private cdr: ChangeDetectorRef, private nzMessageService: NzMessageService, private activatedRoute: ActivatedRoute, - private messageService: MessageService, - private nzModalService: NzModalService + private messageService: MessageService ) {} ngOnInit() { diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html index 1c42f87b371..e2866272e97 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -48,6 +48,7 @@ (editorHideChange)="commitParagraph()" (enabledChange)="commitParagraph()" (titleChange)="commitParagraph()" + (openSingleParagraph)="openSingleParagraph($event)" (runOnSelectionChangeChange)="commitParagraph()" (runParagraph)="runParagraph()" (moveUp)="moveUpParagraph()" diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index f5b61e8006f..246d09e7aad 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -29,25 +29,10 @@ import { import { merge, Observable, Subject } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import DiffMatchPatch from 'diff-match-patch'; -import { isEmpty, isEqual } from 'lodash'; import { NzModalService } from 'ng-zorro-antd/modal'; -import { MessageListener, MessageListenersManager } from '@zeppelin/core'; -import { - AngularObjectRemove, - AngularObjectUpdate, - GraphConfig, - InterpreterBindingItem, - MessageReceiveDataTypeMap, - Note, - OP, - ParagraphConfig, - ParagraphConfigResult, - ParagraphEditorSetting, - ParagraphItem, - ParagraphIResultsMsgItem -} from '@zeppelin/sdk'; +import { ParagraphBase } from '@zeppelin/core'; +import { InterpreterBindingItem, Note, ParagraphConfigResult, ParagraphItem } from '@zeppelin/sdk'; import { HeliumService, MessageService, @@ -55,7 +40,6 @@ import { NoteStatusService, NoteVarShareService, ParagraphActions, - ParagraphStatus, ShortcutsMap, ShortcutService } from '@zeppelin/services'; @@ -63,8 +47,8 @@ import { SpellResult } from '@zeppelin/spell/spell-result'; import { NgTemplateAdapterService } from '@zeppelin/services/ng-template-adapter.service'; import { NzResizeEvent } from 'ng-zorro-antd/resizable'; +import { NotebookParagraphResultComponent } from '../../share/result/result.component'; import { NotebookParagraphCodeEditorComponent } from './code-editor/code-editor.component'; -import { NotebookParagraphResultComponent } from './result/result.component'; type Mode = 'edit' | 'command'; @@ -78,7 +62,7 @@ type Mode = 'edit' | 'command'; }, changeDetection: ChangeDetectionStrategy.OnPush }) -export class NotebookParagraphComponent extends MessageListenersManager implements OnInit, OnChanges, OnDestroy { +export class NotebookParagraphComponent extends ParagraphBase implements OnInit, OnChanges, OnDestroy { @ViewChild(NotebookParagraphCodeEditorComponent, { static: false }) notebookParagraphCodeEditorComponent: NotebookParagraphCodeEditorComponent; @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList< @@ -103,105 +87,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen private destroy$ = new Subject(); private mode: Mode = 'command'; waitConfirmFromEdit = false; - dirtyText: string; - originalText: string; - isEntireNoteRunning = false; - diffMatchPatch = new DiffMatchPatch(); - isParagraphRunning = false; - results = []; - configs = {}; - progress = 0; - colWidthOption = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; - editorSetting: ParagraphEditorSetting = {}; - - @MessageListener(OP.PROGRESS) - onProgress(data: MessageReceiveDataTypeMap[OP.PROGRESS]) { - if (data.id === this.paragraph.id) { - this.progress = data.progress; - this.cdr.markForCheck(); - } - } - - @MessageListener(OP.NOTE_RUNNING_STATUS) - noteRunningStatusChange(data: MessageReceiveDataTypeMap[OP.NOTE_RUNNING_STATUS]) { - this.isEntireNoteRunning = data.status; - this.cdr.markForCheck(); - } - - @MessageListener(OP.PARAS_INFO) - updateParaInfos(data: MessageReceiveDataTypeMap[OP.PARAS_INFO]) { - if (this.paragraph.id === data.id) { - this.paragraph.runtimeInfos = data.infos; - this.cdr.markForCheck(); - } - } - - @MessageListener(OP.EDITOR_SETTING) - getEditorSetting(data: MessageReceiveDataTypeMap[OP.EDITOR_SETTING]) { - if (this.paragraph.id === data.paragraphId) { - this.paragraph.config.editorSetting = { ...this.paragraph.config.editorSetting, ...data.editor }; - this.cdr.markForCheck(); - } - } - - @MessageListener(OP.PARAGRAPH) - paragraphData(data: MessageReceiveDataTypeMap[OP.PARAGRAPH]) { - const oldPara = this.paragraph; - const newPara = data.paragraph; - if (this.isUpdateRequired(oldPara, newPara)) { - this.updateParagraph(oldPara, newPara, () => { - if (newPara.results && newPara.results.msg) { - // tslint:disable-next-line:no-for-in-array - for (const i in newPara.results.msg) { - if (newPara.results.msg[i]) { - const newResult = newPara.results.msg ? newPara.results.msg[i] : new ParagraphIResultsMsgItem(); - const oldResult = - oldPara.results && oldPara.results.msg ? oldPara.results.msg[i] : new ParagraphIResultsMsgItem(); - const newConfig = newPara.config.results ? newPara.config.results[i] : { graph: new GraphConfig() }; - const oldConfig = oldPara.config.results ? oldPara.config.results[i] : { graph: new GraphConfig() }; - if (!isEqual(newResult, oldResult) || !isEqual(newConfig, oldConfig)) { - const resultComponent = this.notebookParagraphResultComponents.toArray()[i]; - if (resultComponent) { - resultComponent.updateResult(newConfig, newResult); - } - } - } - } - } - this.cdr.markForCheck(); - }); - this.cdr.markForCheck(); - } - } - - @MessageListener(OP.PATCH_PARAGRAPH) - patchParagraph(data: MessageReceiveDataTypeMap[OP.PATCH_PARAGRAPH]) { - if (data.paragraphId === this.paragraph.id) { - let patch = data.patch; - patch = this.diffMatchPatch.patch_fromText(patch); - if (!this.paragraph.text) { - this.paragraph.text = ''; - } - this.paragraph.text = this.diffMatchPatch.patch_apply(patch, this.paragraph.text)[0]; - this.originalText = this.paragraph.text; - this.cdr.markForCheck(); - } - } - - @MessageListener(OP.ANGULAR_OBJECT_UPDATE) - angularObjectUpdate(data: AngularObjectUpdate) { - if (data.paragraphId === this.paragraph.id) { - const { name, object } = data.angularObject; - this.ngZService.setContextValue(name, object, data.paragraphId, false); - } - } - - @MessageListener(OP.ANGULAR_OBJECT_REMOVE) - angularObjectRemove(data: AngularObjectRemove) { - if (data.paragraphId === this.paragraph.id) { - this.ngZService.unsetContextValue(data.name, data.paragraphId, false); - } - } switchMode(mode: Mode): void { if (mode === this.mode) { @@ -215,35 +100,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen } } - updateParagraph(oldPara: ParagraphItem, newPara: ParagraphItem, updateCallback: () => void) { - // 1. can't update on revision view - if (!this.revisionView) { - // 2. get status, refreshed - const statusChanged = newPara.status !== oldPara.status; - const resultRefreshed = - newPara.dateFinished !== oldPara.dateFinished || - isEmpty(newPara.results) !== isEmpty(oldPara.results) || - newPara.status === ParagraphStatus.ERROR || - (newPara.status === ParagraphStatus.FINISHED && statusChanged); - - // 3. update texts managed by paragraph - this.updateAllScopeTexts(oldPara, newPara); - // 4. execute callback to update result - updateCallback(); - - // 5. update remaining paragraph objects - this.updateParagraphObjectWhenUpdated(newPara); - - // 6. handle scroll down by key properly if new paragraph is added - if (statusChanged || resultRefreshed) { - // when last paragraph runs, zeppelin automatically appends new paragraph. - // this broadcast will focus to the newly inserted paragraph - // TODO(hsuanxyz) - } - this.cdr.markForCheck(); - } - } - textChanged(text: string) { this.dirtyText = text; this.paragraph.text = text; @@ -472,94 +328,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen } } - runParagraphUsingSpell(paragraphText: string, magic: string, propagated: boolean) { - // TODO(hsuanxyz) - } - - runParagraphUsingBackendInterpreter(paragraphText: string) { - this.messageService.runParagraph( - this.paragraph.id, - this.paragraph.title, - paragraphText, - this.paragraph.config, - this.paragraph.settings.params - ); - } - - cancelParagraph() { - if (!this.isEntireNoteRunning) { - this.messageService.cancelParagraph(this.paragraph.id); - } - } - - updateAllScopeTexts(oldPara: ParagraphItem, newPara: ParagraphItem) { - if (oldPara.text !== newPara.text) { - if (this.dirtyText) { - // check if editor has local update - if (this.dirtyText === newPara.text) { - // when local update is the same from remote, clear local update - this.paragraph.text = newPara.text; - this.dirtyText = undefined; - this.originalText = newPara.text; - } else { - // if there're local update, keep it. - this.paragraph.text = newPara.text; - } - } else { - this.paragraph.text = newPara.text; - this.originalText = newPara.text; - } - } - this.cdr.markForCheck(); - } - - updateParagraphObjectWhenUpdated(newPara: ParagraphItem) { - if (this.paragraph.config.colWidth !== newPara.config.colWidth) { - this.changeColWidth(false); - } - this.paragraph.aborted = newPara.aborted; - this.paragraph.user = newPara.user; - this.paragraph.dateUpdated = newPara.dateUpdated; - this.paragraph.dateCreated = newPara.dateCreated; - this.paragraph.dateFinished = newPara.dateFinished; - this.paragraph.dateStarted = newPara.dateStarted; - this.paragraph.errorMessage = newPara.errorMessage; - this.paragraph.jobName = newPara.jobName; - this.paragraph.title = newPara.title; - this.paragraph.lineNumbers = newPara.lineNumbers; - this.paragraph.status = newPara.status; - this.paragraph.fontSize = newPara.fontSize; - if (newPara.status !== ParagraphStatus.RUNNING) { - this.paragraph.results = newPara.results; - } - this.paragraph.settings = newPara.settings; - this.paragraph.runtimeInfos = newPara.runtimeInfos; - this.isParagraphRunning = this.noteStatusService.isParagraphRunning(newPara); - this.paragraph.config = newPara.config; - this.initializeDefault(this.paragraph.config); - this.setResults(); - this.cdr.markForCheck(); - } - - isUpdateRequired(oldPara: ParagraphItem, newPara: ParagraphItem): boolean { - return ( - newPara.id === oldPara.id && - (newPara.dateCreated !== oldPara.dateCreated || - newPara.text !== oldPara.text || - newPara.dateFinished !== oldPara.dateFinished || - newPara.dateStarted !== oldPara.dateStarted || - newPara.dateUpdated !== oldPara.dateUpdated || - newPara.status !== oldPara.status || - newPara.jobName !== oldPara.jobName || - newPara.title !== oldPara.title || - isEmpty(newPara.results) !== isEmpty(oldPara.results) || - newPara.errorMessage !== oldPara.errorMessage || - !isEqual(newPara.settings, oldPara.settings) || - !isEqual(newPara.config, oldPara.config) || - !isEqual(newPara.runtimeInfos, oldPara.runtimeInfos)) - ); - } - insertParagraph(position: string) { if (this.revisionView === true) { return; @@ -584,16 +352,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen this.cdr.markForCheck(); } - setResults() { - if (this.paragraph.results) { - this.results = this.paragraph.results.msg; - this.configs = this.paragraph.config.results; - } - if (!this.paragraph.config) { - this.paragraph.config = {}; - } - } - setTitle(title: string) { this.paragraph.title = title; this.commitParagraph(); @@ -611,42 +369,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen this.cdr.markForCheck(); } - initializeDefault(config: ParagraphConfig) { - const forms = this.paragraph.settings.forms; - - if (!config.colWidth) { - config.colWidth = 12; - } - - if (!config.fontSize) { - config.fontSize = 9; - } - - if (config.enabled === undefined) { - config.enabled = true; - } - - for (const idx in forms) { - if (forms[idx]) { - if (forms[idx].options) { - if (config.runOnSelectionChange === undefined) { - config.runOnSelectionChange = true; - } - } - } - } - - if (!config.results) { - config.results = {}; - } - - if (!config.editorSetting) { - config.editorSetting = {}; - } else if (config.editorSetting.editOnDblClick) { - this.editorSetting.isOutputHidden = config.editorSetting.editOnDblClick; - } - } - moveUpParagraph() { const newIndex = this.note.paragraphs.findIndex(p => p.id === this.paragraph.id) - 1; if (newIndex < 0 || newIndex >= this.note.paragraphs.length) { @@ -709,23 +431,29 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen this.cdr.markForCheck(); } + openSingleParagraph(paragraphId: string): void { + const noteId = this.note.id; + const redirectToUrl = `${location.protocol}//${location.host}${location.pathname}#/notebook/${noteId}/paragraph/${paragraphId}`; + window.open(redirectToUrl); + } + trackByIndexFn(index: number) { return index; } constructor( + noteStatusService: NoteStatusService, + cdr: ChangeDetectorRef, + ngZService: NgZService, private heliumService: HeliumService, - private noteStatusService: NoteStatusService, public messageService: MessageService, private nzModalService: NzModalService, private noteVarShareService: NoteVarShareService, - private cdr: ChangeDetectorRef, - private ngZService: NgZService, private shortcutService: ShortcutService, private host: ElementRef, private ngTemplateAdapterService: NgTemplateAdapterService ) { - super(messageService); + super(messageService, noteStatusService, ngZService, cdr); } ngOnInit() { @@ -823,6 +551,9 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen } } switch (action) { + case ParagraphActions.Link: + this.openSingleParagraph(this.paragraph.id); + break; case ParagraphActions.EditMode: if (this.mode === 'command') { event.preventDefault(); @@ -847,7 +578,6 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen break; } }); - this.setResults(); this.originalText = this.paragraph.text; this.isEntireNoteRunning = this.noteStatusService.isEntireNoteRunning(this.note); @@ -894,6 +624,5 @@ export class NotebookParagraphComponent extends MessageListenersManager implemen ngOnDestroy(): void { super.ngOnDestroy(); - this.ngZService.removeParagraph(this.paragraph.id); } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html new file mode 100644 index 00000000000..d69a0f43424 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html @@ -0,0 +1,15 @@ + + + + diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.less new file mode 100644 index 00000000000..e69de29bb2d diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts new file mode 100644 index 00000000000..12e10de7914 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts @@ -0,0 +1,88 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { MessageListener, ParagraphBase } from '@zeppelin/core'; +import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published'; +import { NotebookParagraphResultComponent } from '@zeppelin/pages/workspace/share/result/result.component'; +import { MessageReceiveDataTypeMap, Note, OP } from '@zeppelin/sdk'; +import { HeliumService, MessageService, NgZService, NoteStatusService } from '@zeppelin/services'; +import { SpellResult } from '@zeppelin/spell/spell-result'; +import { isNil } from 'lodash'; + +@Component({ + selector: 'zeppelin-publish-paragraph', + templateUrl: './paragraph.component.html', + styleUrls: ['./paragraph.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class PublishedParagraphComponent extends ParagraphBase implements Published, OnInit { + readonly [publishedSymbol] = true; + + noteId: string; + paragraphId: string; + + @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList< + NotebookParagraphResultComponent + >; + + constructor( + public messageService: MessageService, + noteStatusService: NoteStatusService, + ngZService: NgZService, + cdr: ChangeDetectorRef, + private activatedRoute: ActivatedRoute, + private heliumService: HeliumService + ) { + super(messageService, noteStatusService, ngZService, cdr); + this.activatedRoute.params.subscribe(params => { + this.noteId = params.noteId; + this.paragraphId = params.paragraphId; + this.messageService.getNote(this.noteId); + }); + } + + ngOnInit() {} + + @MessageListener(OP.NOTE) + getNote(data: MessageReceiveDataTypeMap[OP.NOTE]) { + const note = data.note; + if (!isNil(note)) { + this.paragraph = (note as Note['note']).paragraphs.find(p => p.id === this.paragraphId); + if (this.paragraph) { + this.setResults(); + this.originalText = this.paragraph.text; + this.initializeDefault(this.paragraph.config); + } + } + this.cdr.markForCheck(); + } + + trackByIndexFn(index: number) { + return index; + } + + setResults() { + if (this.paragraph.results) { + this.results = this.paragraph.results.msg; + this.configs = this.paragraph.config.results; + } + if (!this.paragraph.config) { + this.paragraph.config = {}; + } + } + + changeColWidth(needCommit: boolean, updateResult?: boolean): void { + // noop + } + + runParagraph(): void { + const text = this.paragraph.text; + if (text && !this.isParagraphRunning) { + const magic = SpellResult.extractMagic(this.paragraph.text); + if (this.heliumService.getSpellByMagic(magic)) { + this.runParagraphUsingSpell(text, magic, false); + } else { + this.runParagraphUsingBackendInterpreter(text); + } + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts new file mode 100644 index 00000000000..eaf001fde06 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/published-ruoting.module.ts @@ -0,0 +1,28 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { PublishedParagraphComponent } from './paragraph/paragraph.component'; + +const routes: Routes = [ + { + path: ':paragraphId', + component: PublishedParagraphComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class PublishedRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts new file mode 100644 index 00000000000..f6474d94896 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts @@ -0,0 +1,11 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { WorkspaceShareModule } from '../../workspace/share/share.module'; +import { PublishedParagraphComponent } from './paragraph/paragraph.component'; +import { PublishedRoutingModule } from './published-ruoting.module'; + +@NgModule({ + declarations: [PublishedParagraphComponent], + imports: [CommonModule, WorkspaceShareModule, PublishedRoutingModule] +}) +export class PublishedModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html similarity index 100% rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.html rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less similarity index 100% rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.less rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts similarity index 100% rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/dynamic-forms/dynamic-forms.component.ts rename to zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/index.ts b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts new file mode 100644 index 00000000000..e865360a6bb --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/public-api.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './share.module'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html similarity index 95% rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html index fe34a372d69..0b246b0efbf 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html @@ -10,7 +10,7 @@ ~ limitations under the License. --> -
+
-
{{plainText}}
+
img
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less similarity index 100% rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.less rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts similarity index 99% rename from zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts rename to zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts index 742a9fb29a8..86d94cce9a0 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/result/result.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts @@ -68,6 +68,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, @Input() result: ParagraphIResultsMsgItem; @Input() config: ParagraphConfigResult; @Input() id: string; + @Input() published = false; @Input() currentCol = 12; @Output() readonly configChange = new EventEmitter(); @Output() readonly sizeChange = new EventEmitter(); @@ -223,6 +224,9 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, break; } this.cdr.markForCheck(); + if (this.published) { + this.cdr.detectChanges(); + } } renderHTML(): void { diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts new file mode 100644 index 00000000000..4c7ef1d0ce9 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts @@ -0,0 +1,56 @@ +/* + * 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 { PortalModule } from '@angular/cdk/portal'; +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +import { + NzButtonModule, + NzCheckboxModule, + NzDropDownModule, + NzIconModule, + NzRadioModule, + NzSelectModule, + NzSwitchModule, + NzToolTipModule +} from 'ng-zorro-antd'; +import { NzResizableModule } from 'ng-zorro-antd/resizable'; + +import { ShareModule } from '@zeppelin/share'; +import { VisualizationModule } from '@zeppelin/visualizations/visualization.module'; + +import { NotebookParagraphDynamicFormsComponent } from './dynamic-forms/dynamic-forms.component'; +import { NotebookParagraphResultComponent } from './result/result.component'; + +@NgModule({ + exports: [NotebookParagraphResultComponent, NotebookParagraphDynamicFormsComponent], + declarations: [NotebookParagraphResultComponent, NotebookParagraphDynamicFormsComponent], + imports: [ + CommonModule, + ShareModule, + PortalModule, + VisualizationModule, + FormsModule, + NzButtonModule, + NzDropDownModule, + NzRadioModule, + NzResizableModule, + NzToolTipModule, + NzIconModule, + NzCheckboxModule, + NzSelectModule, + NzSwitchModule + ] +}) +export class WorkspaceShareModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts index 0340a8d1499..93154434da7 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts @@ -30,6 +30,10 @@ const routes: Routes = [ path: 'notebook', loadChildren: () => import('@zeppelin/pages/workspace/notebook/notebook.module').then(m => m.NotebookModule) }, + { + path: 'notebook/:noteId/paragraph', + loadChildren: () => import('@zeppelin/pages/workspace/published/published.module').then(m => m.PublishedModule) + }, { path: 'jobmanager', loadChildren: () => diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html index 6bcae47ad44..c41cf78dbec 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html @@ -11,7 +11,7 @@ -->
- - + +
Connecting WebSocket ... diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts index 03c5b9b0f75..c89d287edc7 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts @@ -12,10 +12,13 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { filter, map, startWith, takeUntil, tap } from 'rxjs/operators'; +import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router'; +import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published'; import { HeliumManagerService } from '@zeppelin/helium-manager'; import { MessageService } from '@zeppelin/services'; +import { log } from 'ng-zorro-antd'; @Component({ selector: 'zeppelin-workspace', @@ -26,6 +29,7 @@ import { MessageService } from '@zeppelin/services'; export class WorkspaceComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); websocketConnected = false; + publishMode = false; constructor( public messageService: MessageService, @@ -33,6 +37,11 @@ export class WorkspaceComponent implements OnInit, OnDestroy { private heliumManagerService: HeliumManagerService ) {} + onActivate(e) { + this.publishMode = e && e[publishedSymbol]; + this.cdr.markForCheck(); + } + ngOnInit() { this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(data => { this.websocketConnected = data; diff --git a/zeppelin-web-angular/src/app/services/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts index b6d6a3aac18..4b2a62627a6 100644 --- a/zeppelin-web-angular/src/app/services/shortcut.service.ts +++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts @@ -1,7 +1,7 @@ -import {DOCUMENT} from "@angular/common"; -import {Inject, Injectable} from '@angular/core'; -import {EventManager} from "@angular/platform-browser"; -import {Observable} from "rxjs"; +import { DOCUMENT } from '@angular/common'; +import { Inject, Injectable } from '@angular/core'; +import { EventManager } from '@angular/platform-browser'; +import { Observable } from 'rxjs'; export enum ParagraphActions { EditMode = 'Paragraph:EditMode', @@ -23,7 +23,8 @@ export enum ParagraphActions { SwitchTitleShow = 'Paragraph:SwitchTitleShow', SwitchOutputShow = 'Paragraph:SwitchOutputShow', SwitchEditorShow = 'Paragraph:SwitchEditorShow', - SwitchEnable = 'Paragraph:SwitchEnable' + SwitchEnable = 'Paragraph:SwitchEnable', + Link = 'Paragraph:Link' } export const ShortcutsMap = { @@ -34,6 +35,8 @@ export const ShortcutsMap = { [ParagraphActions.Cancel]: 'shift.ctrlCmd.c', // Need register special character `¬` in MacOS [ParagraphActions.Clear]: ['alt.ctrlCmd.l', 'alt.ctrlCmd.¬'], + // Need register special character `†` in MacOS + [ParagraphActions.Link]: ['alt.ctrlCmd.t', 'alt.ctrlCmd.†'], // Need register special character `®` in MacOS [ParagraphActions.SwitchEnable]: ['alt.ctrlCmd.r', 'alt.ctrlCmd.®'], // Need register special character `–` in MacOS @@ -54,28 +57,27 @@ export const ShortcutsMap = { }; export interface ShortcutEvent { - event: KeyboardEvent + event: KeyboardEvent; keybindings: string; } export interface ShortcutOption { - scope?: HTMLElement, - keybindings: string + scope?: HTMLElement; + keybindings: string; } function isMacOS() { - return navigator.platform.indexOf('Mac') > -1 + return navigator.platform.indexOf('Mac') > -1; } @Injectable({ providedIn: 'root' }) export class ShortcutService { - private element: HTMLElement; - constructor(private eventManager: EventManager, - @Inject(DOCUMENT) _document: any) { + // tslint:disable-next-line:no-any + constructor(private eventManager: EventManager, @Inject(DOCUMENT) _document: any) { this.element = _document; } @@ -86,9 +88,9 @@ export class ShortcutService { bindShortcut(option: ShortcutOption): Observable { const host = option.scope || this.element; // `ctrlCmd` is special symbol, will be replaced `meta` in MacOS, 'control' in Windows/Linux - const keybindings = option.keybindings - .replace(/ctrlCmd/g, isMacOS() ? 'meta' : 'control'); - const event = `keydown.${keybindings}`; + const keybindings = option.keybindings.replace(/ctrlCmd/g, isMacOS() ? 'meta' : 'control'); + const eventName = `keydown.${keybindings}`; + // tslint:disable-next-line:ban-types let dispose: Function; return new Observable(observer => { const handler = event => { @@ -98,12 +100,11 @@ export class ShortcutService { }); }; - dispose = this.eventManager.addEventListener(host, event, handler); + dispose = this.eventManager.addEventListener(host, eventName, handler); return () => { dispose(); }; - }) + }); } - } From 1edc985da91d054208e83f98244711bda5913d9c Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Tue, 3 Dec 2019 15:18:13 +0800 Subject: [PATCH 11/32] [ZEPPELIN-4401] Add configuration page ### What is this PR for? Add the configuration page on the reworked with Angular project ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4401 ### How should this be tested? Not applicable ### Screenshots (if appropriate) ![image](https://user-images.githubusercontent.com/22736418/70121058-cb56c680-16a8-11ea-9ee5-3375a2bc76d6.png) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3532 from hsuanxyz/feat/configuration and squashes the following commits: 2e2ee0c2b [Hsuan Lee] feat: add configuration page --- .../configuration-routing.module.ts | 27 ++++++++++++++ .../configuration.component.html | 37 +++++++++++++++++++ .../configuration.component.less | 22 +++++++++++ .../configuration/configuration.component.ts | 36 ++++++++++++++++++ .../configuration/configuration.module.ts | 24 ++++++++++++ .../workspace/workspace-routing.module.ts | 5 +++ .../src/app/services/configuration.service.ts | 30 +++++++++++++++ .../src/app/services/public-api.ts | 1 + .../page-header/page-header.component.html | 2 +- .../page-header/page-header.component.ts | 2 +- .../src/app/share/share.module.ts | 2 + 11 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts create mode 100644 zeppelin-web-angular/src/app/services/configuration.service.ts diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts new file mode 100644 index 00000000000..6d499a0c7bc --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration-routing.module.ts @@ -0,0 +1,27 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ConfigurationComponent } from './configuration.component'; + +const routes: Routes = [ + { + path: '', + component: ConfigurationComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ConfigurationRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html new file mode 100644 index 00000000000..6708f345203 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html @@ -0,0 +1,37 @@ + + + + + Shows current configurations for Zeppelin Server. +
+ Note: For security reasons, some key/value pairs including passwords would not be shown. +
+
+ + + + Name + Value + + + + + {{data[0]}} + {{data[1]}} + + + +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less new file mode 100644 index 00000000000..b3c4ee24e55 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.less @@ -0,0 +1,22 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + .content { + padding: @card-padding-base / 2; + nz-table { + background: @card-background; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts new file mode 100644 index 00000000000..fb3b1205743 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts @@ -0,0 +1,36 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { ConfigurationService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-configuration', + templateUrl: './configuration.component.html', + styleUrls: ['./configuration.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class ConfigurationComponent implements OnInit { + configEntries: Array<[string, string]> = []; + + constructor(private configurationService: ConfigurationService, private cdr: ChangeDetectorRef) {} + + ngOnInit() { + this.getAllConfig(); + } + + getAllConfig(): void { + this.configurationService.getAll().subscribe(data => { + this.configEntries = [...Object.entries(data)]; + this.cdr.markForCheck(); + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts new file mode 100644 index 00000000000..ff64f8932c4 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts @@ -0,0 +1,24 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { ShareModule } from '@zeppelin/share'; +import { NzTableModule } from 'ng-zorro-antd'; +import { ConfigurationRoutingModule } from './configuration-routing.module'; +import { ConfigurationComponent } from './configuration.component'; + +@NgModule({ + declarations: [ConfigurationComponent], + imports: [CommonModule, ShareModule, NzTableModule, ConfigurationRoutingModule] +}) +export class ConfigurationModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts index 93154434da7..1b6bedf03ea 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts @@ -43,6 +43,11 @@ const routes: Routes = [ path: 'interpreter', loadChildren: () => import('@zeppelin/pages/workspace/interpreter/interpreter.module').then(m => m.InterpreterModule) + }, + { + path: 'configuration', + loadChildren: () => + import('@zeppelin/pages/workspace/configuration/configuration.module').then(m => m.ConfigurationModule) } ] } diff --git a/zeppelin-web-angular/src/app/services/configuration.service.ts b/zeppelin-web-angular/src/app/services/configuration.service.ts new file mode 100644 index 00000000000..b8c392f0ff4 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/configuration.service.ts @@ -0,0 +1,30 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ConfigurationService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getAll() { + return this.http.get<{ [key: string]: string }>(this.restUrl`/configurations/all`); + } +} diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts index d6709ac83e8..155a3b2e80f 100644 --- a/zeppelin-web-angular/src/app/services/public-api.ts +++ b/zeppelin-web-angular/src/app/services/public-api.ts @@ -27,3 +27,4 @@ export * from './array-ordering.service'; export * from './note-list.service'; export * from './runtime-compiler.service'; export * from './shortcut.service'; +export * from './configuration.service'; diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.html b/zeppelin-web-angular/src/app/share/page-header/page-header.component.html index 430f7e2880b..c214ab41ff4 100644 --- a/zeppelin-web-angular/src/app/share/page-header/page-header.component.html +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.html @@ -12,7 +12,7 @@

{{title}}

-

{{description}}

+

{{description}}

diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts index 1c03ee6298c..601726eed30 100644 --- a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts @@ -21,7 +21,7 @@ import { InputBoolean } from 'ng-zorro-antd'; }) export class PageHeaderComponent implements OnInit { @Input() title: string; - @Input() description: string; + @Input() description: string | TemplateRef; @Input() @InputBoolean() divider = false; @Input() extra: TemplateRef; diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts index fcb03751092..3f7a003b1b1 100644 --- a/zeppelin-web-angular/src/app/share/share.module.ts +++ b/zeppelin-web-angular/src/app/share/share.module.ts @@ -16,6 +16,7 @@ import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { + NzAddOnModule, NzAlertModule, NzBadgeModule, NzButtonModule, @@ -74,6 +75,7 @@ const PIPES = [HumanizeBytesPipe]; FormsModule, CommonModule, NzMenuModule, + NzAddOnModule, NzIconModule, NzInputModule, NzDropDownModule, From 3aaa1113cc9c35e6fe13289df4612a4e30041444 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Wed, 4 Dec 2019 15:08:11 +0800 Subject: [PATCH 12/32] [ZEPPELIN-4399] Add credential page ### What is this PR for? Add the credential page on the reworked with Angular project ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4399 ### How should this be tested? Not applicable ### Screenshots (if appropriate) ![credential](https://user-images.githubusercontent.com/22736418/70136543-2697b180-16c7-11ea-9aa3-0e44b3312b78.gif) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3537 from hsuanxyz/feat/credential and squashes the following commits: 9fc6a9d24 [Hsuan Lee] feat: add credential page --- .../src/app/interfaces/credential.ts | 28 +++ .../src/app/interfaces/public-api.ts | 1 + .../credential/credential-routing.module.ts | 28 +++ .../credential/credential.component.html | 134 ++++++++++++ .../credential/credential.component.less | 39 ++++ .../credential/credential.component.ts | 201 ++++++++++++++++++ .../workspace/credential/credential.module.ts | 56 +++++ .../workspace/workspace-routing.module.ts | 5 + .../src/app/services/credential.service.ts | 43 ++++ .../src/app/services/public-api.ts | 1 + 10 files changed, 536 insertions(+) create mode 100644 zeppelin-web-angular/src/app/interfaces/credential.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts create mode 100644 zeppelin-web-angular/src/app/services/credential.service.ts diff --git a/zeppelin-web-angular/src/app/interfaces/credential.ts b/zeppelin-web-angular/src/app/interfaces/credential.ts new file mode 100644 index 00000000000..533b1206819 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/credential.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +export interface Credential { + userCredentials: { + [key: string]: CredentialItem; + }; +} + +export interface CredentialItem { + username: string; + password: string; +} + +export interface CredentialForm { + entity: string; + password: string; + username: string; +} diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/public-api.ts index 1e07b8e496a..f00e442594e 100644 --- a/zeppelin-web-angular/src/app/interfaces/public-api.ts +++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts @@ -15,3 +15,4 @@ export * from './trash-folder-id'; export * from './interpreter'; export * from './message-interceptor'; export * from './security'; +export * from './credential'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts new file mode 100644 index 00000000000..5624c7e28ba --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential-routing.module.ts @@ -0,0 +1,28 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { CredentialComponent } from './credential.component'; + +const routes: Routes = [ + { + path: '', + component: CredentialComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class CredentialRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html new file mode 100644 index 00000000000..51b0c84c208 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html @@ -0,0 +1,134 @@ + + + + + Manage your credentials. You can add new credential information. + + + + + + + +
+ +

Add new credential

+
+
+
+ + Entity + + + + + {{ option }} + + + + + + Username + + + + + + Password + + + + +
+
+ + + + + + +
+
+
+
+
+
+ + + + Entity + Username + Password + Actions + + + + + + {{entity}} + + + + + + + + + + + + {{control.get('username')?.value}} + ********** + + + + + + + + + + +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less new file mode 100644 index 00000000000..87649caf0a5 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less @@ -0,0 +1,39 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + ::ng-deep { + .ant-form-inline .ant-form-item-with-help { + margin-bottom: 0; + } + + .credential-actions, .new-actions { + text-align: right; + button+button { + margin-left: 8px; + } + } + + .actions-head { + text-align: right; + } + } + + .content { + padding: @card-padding-base / 2; + nz-table { + background: @card-background; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts new file mode 100644 index 00000000000..47150dbd69f --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts @@ -0,0 +1,201 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { collapseMotion, NzMessageService } from 'ng-zorro-antd'; + +import { finalize } from 'rxjs/operators'; + +import { CredentialForm } from '@zeppelin/interfaces'; +import { CredentialService, InterpreterService, TicketService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-credential', + templateUrl: './credential.component.html', + styleUrls: ['./credential.component.less'], + animations: [collapseMotion], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CredentialComponent implements OnInit { + addForm: FormGroup; + showAdd = false; + adding = false; + interpreterNames: string[] = []; + interpreterFilteredNames: string[] = []; + editFlags: Map = new Map(); + credentialFormArray: FormArray = this.fb.array([]); + docsLink: string; + + get credentialControls(): FormGroup[] { + return this.credentialFormArray.controls as FormGroup[]; + } + + constructor( + private cdr: ChangeDetectorRef, + private fb: FormBuilder, + private nzMessageService: NzMessageService, + private interpreterService: InterpreterService, + private credentialService: CredentialService, + private ticketService: TicketService + ) { + this.setDocsLink(); + } + + setDocsLink() { + const version = this.ticketService.version; + this.docsLink = `https://zeppelin.apache.org/docs/${version}/setup/security/datasource_authorization.html`; + } + + onEntityInput(event: Event) { + const input = event.target as HTMLInputElement; + if (input && input.value) { + this.interpreterFilteredNames = this.interpreterNames + .filter(e => e.indexOf(input.value.trim()) !== -1) + .slice(0, 10); + } else { + this.interpreterFilteredNames = this.interpreterNames.slice(0, 10); + } + } + + getEntityFromForm(form: FormGroup): string { + return form.get('entity') && form.get('entity').value; + } + + isEditing(form: FormGroup): boolean { + const entity = this.getEntityFromForm(form); + return entity && this.editFlags.has(entity); + } + + setEditable(form: FormGroup) { + const entity = this.getEntityFromForm(form); + if (entity) { + this.editFlags.set(entity, form.getRawValue()); + } + this.cdr.markForCheck(); + } + + unsetEditable(form: FormGroup, reset = true) { + const entity = this.getEntityFromForm(form); + if (reset && entity && this.editFlags.has(entity)) { + form.reset(this.editFlags.get(entity)); + } + this.editFlags.delete(entity); + this.cdr.markForCheck(); + } + + submitForm(): void { + for (const i in this.addForm.controls) { + this.addForm.controls[i].markAsDirty(); + this.addForm.controls[i].updateValueAndValidity(); + } + if (this.addForm.valid) { + const data = this.addForm.getRawValue() as CredentialForm; + this.addCredential(data); + } + } + + saveCredential(form: FormGroup) { + for (const i in form.controls) { + form.controls[i].markAsDirty(); + form.controls[i].updateValueAndValidity(); + } + if (form.valid) { + this.credentialService.updateCredential(form.getRawValue()).subscribe(() => { + this.nzMessageService.success('Successfully saved credentials.'); + this.unsetEditable(form, false); + }); + } + } + + removeCredential(form: FormGroup) { + const entity = this.getEntityFromForm(form); + if (entity) { + this.credentialService.removeCredential(entity).subscribe(() => { + this.getCredentials(); + }); + } + } + + triggerAdd(): void { + this.showAdd = !this.showAdd; + this.cdr.markForCheck(); + } + + cancelAdd() { + this.showAdd = false; + this.resetAddForm(); + this.cdr.markForCheck(); + } + + getCredentials() { + this.credentialService.getCredentials().subscribe(data => { + const controls = [...Object.entries(data.userCredentials)].map(e => { + const entity = e[0]; + const { username, password } = e[1]; + return this.fb.group({ + entity: [entity, [Validators.required]], + username: [username, [Validators.required]], + password: [password, [Validators.required]] + }); + }); + this.credentialFormArray = this.fb.array(controls); + this.cdr.markForCheck(); + }); + } + + getInterpreterNames() { + this.interpreterService.getInterpretersSetting().subscribe(data => { + this.interpreterNames = data.map(e => `${e.group}.${e.name}`); + this.interpreterFilteredNames = this.interpreterNames.slice(0, 10); + this.cdr.markForCheck(); + }); + } + + addCredential(data: CredentialForm) { + this.adding = true; + this.cdr.markForCheck(); + this.credentialService + .addCredential(data) + .pipe( + finalize(() => { + this.adding = false; + this.cdr.markForCheck(); + }) + ) + .subscribe(() => { + this.nzMessageService.success('Successfully saved credentials.'); + this.getCredentials(); + this.resetAddForm(); + this.cdr.markForCheck(); + }); + } + + resetAddForm() { + this.addForm.reset({ + entity: null, + username: null, + password: null + }); + this.cdr.markForCheck(); + } + + ngOnInit(): void { + this.getCredentials(); + this.getInterpreterNames(); + this.addForm = this.fb.group({ + entity: [null, [Validators.required]], + username: [null, [Validators.required]], + password: [null, [Validators.required]] + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts new file mode 100644 index 00000000000..a1269804cdd --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts @@ -0,0 +1,56 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { ShareModule } from '@zeppelin/share'; +import { + NzAutocompleteModule, + NzButtonModule, + NzCardModule, + NzDividerModule, + NzFormModule, + NzGridModule, + NzIconModule, + NzInputModule, + NzMessageModule, + NzPopconfirmModule, + NzTableModule, + NzToolTipModule +} from 'ng-zorro-antd'; +import { CredentialRoutingModule } from './credential-routing.module'; +import { CredentialComponent } from './credential.component'; + +@NgModule({ + declarations: [CredentialComponent], + imports: [ + CommonModule, + CredentialRoutingModule, + FormsModule, + ShareModule, + ReactiveFormsModule, + NzFormModule, + NzAutocompleteModule, + NzButtonModule, + NzCardModule, + NzIconModule, + NzDividerModule, + NzInputModule, + NzMessageModule, + NzTableModule, + NzPopconfirmModule, + NzGridModule, + NzToolTipModule + ] +}) +export class CredentialModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts index 1b6bedf03ea..6815b8097c2 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts @@ -48,6 +48,11 @@ const routes: Routes = [ path: 'configuration', loadChildren: () => import('@zeppelin/pages/workspace/configuration/configuration.module').then(m => m.ConfigurationModule) + }, + { + path: 'credential', + loadChildren: () => + import('@zeppelin/pages/workspace/credential/credential.module').then(m => m.CredentialModule) } ] } diff --git a/zeppelin-web-angular/src/app/services/credential.service.ts b/zeppelin-web-angular/src/app/services/credential.service.ts new file mode 100644 index 00000000000..0e08f7b2d96 --- /dev/null +++ b/zeppelin-web-angular/src/app/services/credential.service.ts @@ -0,0 +1,43 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { Credential, CredentialForm } from '@zeppelin/interfaces'; +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class CredentialService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getCredentials() { + return this.http.get(this.restUrl`/credential`); + } + + addCredential(data: CredentialForm) { + return this.http.put(this.restUrl`/credential`, data); + } + + updateCredential(data: CredentialForm) { + return this.http.put(this.restUrl`/credential`, data); + } + + removeCredential(entity: string) { + return this.http.delete(this.restUrl`/credential/${entity}`); + } +} diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts index 155a3b2e80f..6c3dbc07ea5 100644 --- a/zeppelin-web-angular/src/app/services/public-api.ts +++ b/zeppelin-web-angular/src/app/services/public-api.ts @@ -28,3 +28,4 @@ export * from './note-list.service'; export * from './runtime-compiler.service'; export * from './shortcut.service'; export * from './configuration.service'; +export * from './credential.service'; From 5ff4050285f4511b033c4ef09760cffccf932d8d Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Fri, 6 Dec 2019 16:18:18 +0800 Subject: [PATCH 13/32] [ZEPPELIN-4398] Add notebook repository page ### What is this PR for? Add the notebook repository page ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4398 ### How should this be tested? Not applicable ### Screenshots (if appropriate) ![repos](https://user-images.githubusercontent.com/22736418/70308435-338edf00-1846-11ea-9030-bcf4ecaf22bb.gif) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3543 from hsuanxyz/feat/notebook-repos and squashes the following commits: d148902f2 [Hsuan Lee] feat: add notebook repository page --- .../src/app/interfaces/notebook-repo.ts | 32 ++++++++ .../src/app/interfaces/public-api.ts | 1 + .../notebook-repos/item/item.component.html | 79 +++++++++++++++++++ .../notebook-repos/item/item.component.less | 37 +++++++++ .../notebook-repos/item/item.component.ts | 78 ++++++++++++++++++ .../notebook-repos-routing.module.ts | 28 +++++++ .../notebook-repos.component.html | 21 +++++ .../notebook-repos.component.less | 20 +++++ .../notebook-repos.component.ts | 51 ++++++++++++ .../notebook-repos/notebook-repos.module.ts | 49 ++++++++++++ .../workspace/workspace-routing.module.ts | 5 ++ .../app/services/notebook-repos.service.ts | 36 +++++++++ .../src/app/services/public-api.ts | 1 + .../app/share/header/header.component.html | 2 +- 14 files changed, 439 insertions(+), 1 deletion(-) create mode 100644 zeppelin-web-angular/src/app/interfaces/notebook-repo.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts create mode 100644 zeppelin-web-angular/src/app/services/notebook-repos.service.ts diff --git a/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts b/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts new file mode 100644 index 00000000000..de037783ca7 --- /dev/null +++ b/zeppelin-web-angular/src/app/interfaces/notebook-repo.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +export interface NotebookRepo { + name: string; + className: string; + settings: NotebookRepoSettingsItem[]; +} + +export interface NotebookRepoPutData { + name: string; + settings: { + [key: string]: string; + }; +} + +export interface NotebookRepoSettingsItem { + type: string; + // tslint:disable-next-line:no-any + value: any[]; + selected: string; + name: string; +} diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts b/zeppelin-web-angular/src/app/interfaces/public-api.ts index f00e442594e..8c54e3d3464 100644 --- a/zeppelin-web-angular/src/app/interfaces/public-api.ts +++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts @@ -16,3 +16,4 @@ export * from './interpreter'; export * from './message-interceptor'; export * from './security'; export * from './credential'; +export * from './notebook-repo'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html new file mode 100644 index 00000000000..3f4875a5bca --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html @@ -0,0 +1,79 @@ + + + + +
+ +
+
+ + +
+
+

Setting

+
+ + + + Name + Value + + + + + {{setting.name}} + + {{setting.selected}} + + + + + + + + + + + + + + +
+ +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less new file mode 100644 index 00000000000..bc6d2805eb8 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less @@ -0,0 +1,37 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + + display: block; + margin-bottom: @card-padding-base; + position: relative; + + ::ng-deep .repo-item { + &.edit { + background: @orange-1; + } + } + + .extra-wrap { + button { + transition: none; + } + button + button { + margin-bottom: 0; + margin-left: 8px; + } + } + +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts new file mode 100644 index 00000000000..f66247c9599 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts @@ -0,0 +1,78 @@ +/* + * 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 { + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges +} from '@angular/core'; +import { FormArray, FormBuilder, Validators } from '@angular/forms'; +import { NotebookRepo } from '@zeppelin/interfaces'; + +@Component({ + selector: 'zeppelin-notebook-repo-item', + templateUrl: './item.component.html', + styleUrls: ['./item.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookRepoItemComponent implements OnChanges { + @Input() repo: NotebookRepo; + @Output() readonly repoChange = new EventEmitter(); + + settingFormArray: FormArray; + editMode = false; + + constructor(private cdr: ChangeDetectorRef, private fb: FormBuilder) {} + + triggerEditMode() { + this.editMode = !this.editMode; + this.cdr.markForCheck(); + } + + save() { + this.settingFormArray.controls.forEach(control => { + control.markAsDirty(); + control.updateValueAndValidity(); + }); + + if (this.settingFormArray.valid) { + const values = this.settingFormArray.getRawValue() as string[]; + values.forEach((value, i) => (this.repo.settings[i].selected = value)); + this.repoChange.emit(this.repo); + this.editMode = false; + this.cdr.markForCheck(); + } + } + + cancel() { + this.buildForm(); + this.editMode = false; + this.cdr.markForCheck(); + } + + buildForm() { + const controls = this.repo.settings.map(setting => { + return this.fb.control(setting.selected, [Validators.required]); + }); + this.settingFormArray = this.fb.array(controls); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.repo) { + this.buildForm(); + } + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts new file mode 100644 index 00000000000..e7e7ca19ad2 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos-routing.module.ts @@ -0,0 +1,28 @@ +/* + * 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 { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { NotebookReposComponent } from './notebook-repos.component'; + +const routes: Routes = [ + { + path: '', + component: NotebookReposComponent + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class NotebookReposRoutingModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html new file mode 100644 index 00000000000..d47ad877782 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html @@ -0,0 +1,21 @@ + + + +
+ + + +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less new file mode 100644 index 00000000000..5a3f8f0b1ff --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.less @@ -0,0 +1,20 @@ +/* + * 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 'theme-mixin'; + +.themeMixin({ + + .content { + padding: @card-padding-base / 2; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts new file mode 100644 index 00000000000..1faffeeeab0 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts @@ -0,0 +1,51 @@ +/* + * 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; +import { NotebookRepo } from '@zeppelin/interfaces'; +import { NotebookRepoService } from '@zeppelin/services'; + +@Component({ + selector: 'zeppelin-notebook-repos', + templateUrl: './notebook-repos.component.html', + styleUrls: ['./notebook-repos.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NotebookReposComponent implements OnInit { + repositories: NotebookRepo[] = []; + + constructor(private notebookRepoService: NotebookRepoService, private cdr: ChangeDetectorRef) {} + + ngOnInit() { + this.getRepos(); + } + + getRepos() { + this.notebookRepoService.getRepos().subscribe(data => { + this.repositories = data.sort((a, b) => a.name.charCodeAt(0) - b.name.charCodeAt(0)); + this.cdr.markForCheck(); + }); + } + + updateRepoSetting(repo: NotebookRepo) { + const data = { + name: repo.className, + settings: {} + }; + repo.settings.forEach(({ name, selected }) => { + data.settings[name] = selected; + }); + + this.notebookRepoService.updateRepo(data).subscribe(() => { + this.getRepos(); + }); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts new file mode 100644 index 00000000000..2bb9d2528a9 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts @@ -0,0 +1,49 @@ +/* + * 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 { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; + +import { ShareModule } from '@zeppelin/share'; + +import { + NzButtonModule, + NzCardModule, + NzFormModule, + NzIconModule, + NzInputModule, + NzSelectModule, + NzTableModule +} from 'ng-zorro-antd'; + +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NotebookRepoItemComponent } from './item/item.component'; +import { NotebookReposRoutingModule } from './notebook-repos-routing.module'; +import { NotebookReposComponent } from './notebook-repos.component'; + +@NgModule({ + declarations: [NotebookReposComponent, NotebookRepoItemComponent], + imports: [ + CommonModule, + ShareModule, + FormsModule, + ReactiveFormsModule, + NotebookReposRoutingModule, + NzCardModule, + NzButtonModule, + NzInputModule, + NzTableModule, + NzIconModule, + NzFormModule, + NzSelectModule + ] +}) +export class NotebookReposModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts index 6815b8097c2..16928a33fc9 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace-routing.module.ts @@ -53,6 +53,11 @@ const routes: Routes = [ path: 'credential', loadChildren: () => import('@zeppelin/pages/workspace/credential/credential.module').then(m => m.CredentialModule) + }, + { + path: 'notebook-repos', + loadChildren: () => + import('@zeppelin/pages/workspace/notebook-repos/notebook-repos.module').then(m => m.NotebookReposModule) } ] } diff --git a/zeppelin-web-angular/src/app/services/notebook-repos.service.ts b/zeppelin-web-angular/src/app/services/notebook-repos.service.ts new file mode 100644 index 00000000000..624599ae0fd --- /dev/null +++ b/zeppelin-web-angular/src/app/services/notebook-repos.service.ts @@ -0,0 +1,36 @@ +/* + * 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 { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; + +import { NotebookRepo, NotebookRepoPutData } from '@zeppelin/interfaces'; + +import { BaseRest } from './base-rest'; +import { BaseUrlService } from './base-url.service'; + +@Injectable({ + providedIn: 'root' +}) +export class NotebookRepoService extends BaseRest { + constructor(baseUrlService: BaseUrlService, private http: HttpClient) { + super(baseUrlService); + } + + getRepos() { + return this.http.get(this.restUrl`/notebook-repositories`); + } + + updateRepo(repo: NotebookRepoPutData) { + return this.http.put(this.restUrl`/notebook-repositories`, repo); + } +} diff --git a/zeppelin-web-angular/src/app/services/public-api.ts b/zeppelin-web-angular/src/app/services/public-api.ts index 6c3dbc07ea5..f9bdfe9554f 100644 --- a/zeppelin-web-angular/src/app/services/public-api.ts +++ b/zeppelin-web-angular/src/app/services/public-api.ts @@ -29,3 +29,4 @@ export * from './runtime-compiler.service'; export * from './shortcut.service'; export * from './configuration.service'; export * from './credential.service'; +export * from './notebook-repos.service'; diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html index 71e8cd7c614..645da9aa22b 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.html +++ b/zeppelin-web-angular/src/app/share/header/header.component.html @@ -47,7 +47,7 @@ Interpreter
  • - Notebook + Notebook Repos
  • From bdc2940d4faa134769d440f30e9539059a26b29e Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Thu, 12 Dec 2019 11:35:34 +0800 Subject: [PATCH 14/32] [ZEPPELIN-4501] Use secondary entry imports ### What is this PR for? Use secondary entry to speed up the build ### What type of PR is it? [Refactoring] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4501 ### How should this be tested? Not applicable ### Screenshots (if appropriate) Not applicable ### Questions: * Does the licenses files need update? no * Is there breaking changes for older versions? no * Does this needs documentation? no Author: Hsuan Lee Closes #3561 from hsuanxyz/refactor/use-secondary-entry and squashes the following commits: 3c3e6e0be [Hsuan Lee] refactor: use secondary entry imports --- zeppelin-web-angular/package-lock.json | 6 + zeppelin-web-angular/package.json | 1 + .../src/app/app-message.interceptor.ts | 3 +- zeppelin-web-angular/src/app/app.module.ts | 4 +- .../src/app/core/public-api.ts | 1 + .../app/core/runtime-dynamic-module/index.ts | 13 ++ .../ng-zorro-antd-module.ts | 148 ++++++++++++++++++ .../core/runtime-dynamic-module/public-api.ts | 13 ++ .../runtime-dynamic-module.module.ts | 10 ++ .../src/app/pages/login/login.module.ts | 5 +- .../configuration/configuration.module.ts | 2 +- .../credential/credential.component.ts | 3 +- .../workspace/credential/credential.module.ts | 26 ++- .../app/pages/workspace/home/home.module.ts | 4 +- .../create-repository-modal.component.ts | 2 +- .../interpreter/interpreter.component.ts | 4 +- .../interpreter/interpreter.module.ts | 38 +++-- .../job-manager/job-manager.component.ts | 2 +- .../job-manager/job-manager.module.ts | 31 ++-- .../notebook-repos/notebook-repos.module.ts | 16 +- .../action-bar/action-bar.component.ts | 3 +- .../interpreter-binding.component.ts | 2 +- .../workspace/notebook/notebook.module.ts | 32 ++-- .../paragraph/control/control.component.ts | 3 +- .../permissions/permissions.component.ts | 3 +- .../workspace/notebook/share/share.module.ts | 2 +- .../dynamic-forms/dynamic-forms.component.ts | 2 +- .../app/pages/workspace/share/share.module.ts | 18 +-- .../pages/workspace/workspace.component.ts | 2 +- .../services/ng-template-adapter.service.ts | 2 +- .../src/app/services/note-action.service.ts | 2 +- .../app/services/runtime-compiler.service.ts | 7 +- .../src/app/services/ticket.service.ts | 2 +- .../folder-rename/folder-rename.component.ts | 2 +- .../src/app/share/header/header.component.ts | 2 +- .../ng1-migration/ng1-migration.component.ts | 2 +- .../share/node-list/node-list.component.ts | 3 +- .../note-create/note-create.component.ts | 2 +- .../note-import/note-import.component.ts | 3 +- .../note-rename/note-rename.component.ts | 2 +- .../page-header/page-header.component.ts | 2 +- .../src/app/share/share.module.ts | 46 +++--- .../table/table-visualization.component.ts | 2 +- .../visualizations/visualization.module.ts | 26 ++- zeppelin-web-angular/tslint.json | 3 +- 45 files changed, 348 insertions(+), 159 deletions(-) create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts create mode 100644 zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index cd5fb2fd43f..da898b09ce3 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -10311,6 +10311,12 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "nz-tslint-rules": { + "version": "0.800.2", + "resolved": "https://registry.npmjs.org/nz-tslint-rules/-/nz-tslint-rules-0.800.2.tgz", + "integrity": "sha512-iMDMG8XYpOlZ/Shr2qomFEaU9ptRmQNkPT8g+BGeZo7LUBrnSTKlvuak2ZWjEMjpgivZIEo861laow18QDuwcQ==", + "dev": true + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 9d9aa934a3f..670c73cc2ce 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -74,6 +74,7 @@ "monaco-editor-webpack-plugin": "^1.7.0", "ng-packagr": "^5.4.0", "ngx-build-plus": "^8.1.5", + "nz-tslint-rules": "^0.800.2", "prettier": "^1.17.0", "protractor": "~5.4.0", "ts-node": "~7.0.0", diff --git a/zeppelin-web-angular/src/app/app-message.interceptor.ts b/zeppelin-web-angular/src/app/app-message.interceptor.ts index 0e9843d8960..02fdf962c6c 100644 --- a/zeppelin-web-angular/src/app/app-message.interceptor.ts +++ b/zeppelin-web-angular/src/app/app-message.interceptor.ts @@ -13,7 +13,8 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; -import { NzModalService, NzNotificationService } from 'ng-zorro-antd'; +import { NzModalService } from 'ng-zorro-antd/modal'; +import { NzNotificationService } from 'ng-zorro-antd/notification'; import { MessageInterceptor } from '@zeppelin/interfaces'; import { MessageReceiveDataTypeMap, OP, WebSocketMessage } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts index ae3347c350b..06be7f4f6f1 100644 --- a/zeppelin-web-angular/src/app/app.module.ts +++ b/zeppelin-web-angular/src/app/app.module.ts @@ -20,7 +20,9 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { Router, RouterModule } from '@angular/router'; import { ZeppelinHeliumModule } from '@zeppelin/helium'; -import { en_US, NzModalService, NzNotificationService, NZ_I18N } from 'ng-zorro-antd'; +import { en_US, NZ_I18N } from 'ng-zorro-antd/i18n'; +import { NzModalService } from 'ng-zorro-antd/modal'; +import { NzNotificationService } from 'ng-zorro-antd/notification'; import { MESSAGE_INTERCEPTOR, TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; import { loadMonacoLanguage } from '@zeppelin/languages'; diff --git a/zeppelin-web-angular/src/app/core/public-api.ts b/zeppelin-web-angular/src/app/core/public-api.ts index 3bcd355ab02..3f334c803b8 100644 --- a/zeppelin-web-angular/src/app/core/public-api.ts +++ b/zeppelin-web-angular/src/app/core/public-api.ts @@ -14,3 +14,4 @@ export * from './message-listener'; export * from './destroy-hook'; export * from './copy-text'; export * from './paragraph-base'; +export * from './runtime-dynamic-module'; diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts new file mode 100644 index 00000000000..42c2d11e210 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts @@ -0,0 +1,148 @@ +/* + * 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 { NgModule } from '@angular/core'; + +import { NzAffixModule } from 'ng-zorro-antd/affix'; +import { NzAlertModule } from 'ng-zorro-antd/alert'; +import { NzAnchorModule } from 'ng-zorro-antd/anchor'; +import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete'; +import { NzAvatarModule } from 'ng-zorro-antd/avatar'; +import { NzBackTopModule } from 'ng-zorro-antd/back-top'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCalendarModule } from 'ng-zorro-antd/calendar'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzCarouselModule } from 'ng-zorro-antd/carousel'; +import { NzCascaderModule } from 'ng-zorro-antd/cascader'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzCollapseModule } from 'ng-zorro-antd/collapse'; +import { NzCommentModule } from 'ng-zorro-antd/comment'; +import { NzNoAnimationModule, NzTransButtonModule, NzWaveModule } from 'ng-zorro-antd/core'; +import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'; +import { NzDescriptionsModule } from 'ng-zorro-antd/descriptions'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDrawerModule } from 'ng-zorro-antd/drawer'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzEmptyModule } from 'ng-zorro-antd/empty'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzI18nModule } from 'ng-zorro-antd/i18n'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzInputNumberModule } from 'ng-zorro-antd/input-number'; +import { NzLayoutModule } from 'ng-zorro-antd/layout'; +import { NzListModule } from 'ng-zorro-antd/list'; +import { NzMentionModule } from 'ng-zorro-antd/mention'; +import { NzMenuModule } from 'ng-zorro-antd/menu'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzNotificationModule } from 'ng-zorro-antd/notification'; +import { NzPageHeaderModule } from 'ng-zorro-antd/page-header'; +import { NzPaginationModule } from 'ng-zorro-antd/pagination'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzPopoverModule } from 'ng-zorro-antd/popover'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzRateModule } from 'ng-zorro-antd/rate'; +import { NzResultModule } from 'ng-zorro-antd/result'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSkeletonModule } from 'ng-zorro-antd/skeleton'; +import { NzSliderModule } from 'ng-zorro-antd/slider'; +import { NzSpinModule } from 'ng-zorro-antd/spin'; +import { NzStatisticModule } from 'ng-zorro-antd/statistic'; +import { NzStepsModule } from 'ng-zorro-antd/steps'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzTabsModule } from 'ng-zorro-antd/tabs'; +import { NzTagModule } from 'ng-zorro-antd/tag'; +import { NzTimePickerModule } from 'ng-zorro-antd/time-picker'; +import { NzTimelineModule } from 'ng-zorro-antd/timeline'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTransferModule } from 'ng-zorro-antd/transfer'; +import { NzTreeModule } from 'ng-zorro-antd/tree'; +import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select'; +import { NzTypographyModule } from 'ng-zorro-antd/typography'; +import { NzUploadModule } from 'ng-zorro-antd/upload'; + +@NgModule({ + exports: [ + NzAffixModule, + NzAlertModule, + NzAnchorModule, + NzAutocompleteModule, + NzAvatarModule, + NzBackTopModule, + NzBadgeModule, + NzButtonModule, + NzBreadCrumbModule, + NzCalendarModule, + NzCardModule, + NzCarouselModule, + NzCascaderModule, + NzCheckboxModule, + NzCollapseModule, + NzCommentModule, + NzDatePickerModule, + NzDescriptionsModule, + NzDividerModule, + NzDrawerModule, + NzDropDownModule, + NzEmptyModule, + NzFormModule, + NzGridModule, + NzI18nModule, + NzIconModule, + NzInputModule, + NzInputNumberModule, + NzLayoutModule, + NzListModule, + NzMentionModule, + NzMenuModule, + NzMessageModule, + NzModalModule, + NzNoAnimationModule, + NzNotificationModule, + NzPageHeaderModule, + NzPaginationModule, + NzPopconfirmModule, + NzPopoverModule, + NzProgressModule, + NzRadioModule, + NzRateModule, + NzResultModule, + NzSelectModule, + NzSkeletonModule, + NzSliderModule, + NzSpinModule, + NzStatisticModule, + NzStepsModule, + NzSwitchModule, + NzTableModule, + NzTabsModule, + NzTagModule, + NzTimePickerModule, + NzTimelineModule, + NzToolTipModule, + NzTransButtonModule, + NzTransferModule, + NzTreeModule, + NzTreeSelectModule, + NzTypographyModule, + NzUploadModule, + NzWaveModule + ] +}) +export class NzModule { + constructor() {} +} diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts new file mode 100644 index 00000000000..a8a0702b5a0 --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/public-api.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './runtime-dynamic-module.module'; diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts new file mode 100644 index 00000000000..d6cb44c8c2f --- /dev/null +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts @@ -0,0 +1,10 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { NzModule } from './ng-zorro-antd-module'; + +@NgModule({ + declarations: [], + exports: [CommonModule, FormsModule, NzModule] +}) +export class RuntimeDynamicModuleModule {} diff --git a/zeppelin-web-angular/src/app/pages/login/login.module.ts b/zeppelin-web-angular/src/app/pages/login/login.module.ts index 46f40a055d5..7a040a69364 100644 --- a/zeppelin-web-angular/src/app/pages/login/login.module.ts +++ b/zeppelin-web-angular/src/app/pages/login/login.module.ts @@ -14,7 +14,10 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { NzButtonModule, NzFormModule, NzIconModule, NzInputModule } from 'ng-zorro-antd'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; import { LoginRoutingModule } from './login-routing.module'; import { LoginComponent } from './login.component'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts index ff64f8932c4..954017082ec 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.module.ts @@ -13,7 +13,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { ShareModule } from '@zeppelin/share'; -import { NzTableModule } from 'ng-zorro-antd'; +import { NzTableModule } from 'ng-zorro-antd/table'; import { ConfigurationRoutingModule } from './configuration-routing.module'; import { ConfigurationComponent } from './configuration.component'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts index 47150dbd69f..b28a6a63dfa 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts @@ -12,7 +12,8 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { collapseMotion, NzMessageService } from 'ng-zorro-antd'; +import { collapseMotion } from 'ng-zorro-antd/core'; +import { NzMessageService } from 'ng-zorro-antd/message'; import { finalize } from 'rxjs/operators'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts index a1269804cdd..39756edb9f4 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts @@ -14,20 +14,18 @@ import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ShareModule } from '@zeppelin/share'; -import { - NzAutocompleteModule, - NzButtonModule, - NzCardModule, - NzDividerModule, - NzFormModule, - NzGridModule, - NzIconModule, - NzInputModule, - NzMessageModule, - NzPopconfirmModule, - NzTableModule, - NzToolTipModule -} from 'ng-zorro-antd'; +import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { CredentialRoutingModule } from './credential-routing.module'; import { CredentialComponent } from './credential.component'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts index 24e59a71853..49a29734486 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts @@ -13,7 +13,9 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { NzGridModule, NzIconModule, NzToolTipModule } from 'ng-zorro-antd'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts index 8dd38c97766..90e02a7f3ed 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts @@ -14,7 +14,7 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { takeUntil } from 'rxjs/operators'; -import { NzModalRef } from 'ng-zorro-antd'; +import { NzModalRef } from 'ng-zorro-antd/modal'; import { DestroyHookComponent } from '@zeppelin/core'; import { CreateInterpreterRepositoryForm } from '@zeppelin/interfaces'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts index 8e216282d19..0507cd8313c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts @@ -14,7 +14,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnIni import { Subject } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; -import { collapseMotion, NzMessageService, NzModalService } from 'ng-zorro-antd'; +import { collapseMotion } from 'ng-zorro-antd/core'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { Interpreter, InterpreterPropertyTypes, InterpreterRepository } from '@zeppelin/interfaces'; import { InterpreterService } from '@zeppelin/services'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts index 37a9a0e10a1..6ed202f1774 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts @@ -13,26 +13,24 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { - NzAlertModule, - NzBadgeModule, - NzButtonModule, - NzCardModule, - NzCheckboxModule, - NzDividerModule, - NzDropDownModule, - NzFormModule, - NzIconModule, - NzInputModule, - NzMessageModule, - NzModalModule, - NzRadioModule, - NzSelectModule, - NzSwitchModule, - NzTableModule, - NzTagModule, - NzToolTipModule -} from 'ng-zorro-antd'; +import { NzAlertModule } from 'ng-zorro-antd/alert'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzTagModule } from 'ng-zorro-antd/tag'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts index 8e426fd383c..fef84410ca2 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts @@ -13,7 +13,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { NzModalService } from 'ng-zorro-antd'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { JobsItem, JobStatus, ListNoteJobs, ListUpdateNoteJobs, OP } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts index 5ce1f07028d..c8b1b18bf28 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts @@ -16,23 +16,20 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; import { IconDefinition } from '@ant-design/icons-angular'; import { ClockCircleOutline, FileOutline, FileUnknownOutline, SearchOutline } from '@ant-design/icons-angular/icons'; -import { - NzBadgeModule, - NzCardModule, - NzDividerModule, - NzEmptyModule, - NzFormModule, - NzGridModule, - NzHighlightModule, - NzIconModule, - NzInputModule, - NzModalModule, - NzProgressModule, - NzSelectModule, - NzSkeletonModule, - NzToolTipModule, - NZ_ICONS -} from 'ng-zorro-antd'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzHighlightModule } from 'ng-zorro-antd/core'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzEmptyModule } from 'ng-zorro-antd/empty'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule, NZ_ICONS } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSkeletonModule } from 'ng-zorro-antd/skeleton'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts index 2bb9d2528a9..9f30074443e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.module.ts @@ -14,15 +14,13 @@ import { NgModule } from '@angular/core'; import { ShareModule } from '@zeppelin/share'; -import { - NzButtonModule, - NzCardModule, - NzFormModule, - NzIconModule, - NzInputModule, - NzSelectModule, - NzTableModule -} from 'ng-zorro-antd'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzTableModule } from 'ng-zorro-antd/table'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NotebookRepoItemComponent } from './item/item.component'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts index f4968d7988f..994acc11cb4 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts @@ -21,7 +21,8 @@ import { Output } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { NzMessageService, NzModalService } from 'ng-zorro-antd'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts index 377a869d1a4..34a9990e829 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts @@ -13,7 +13,7 @@ import { moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output } from '@angular/core'; -import { NzModalService } from 'ng-zorro-antd'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { InterpreterBindingItem } from '@zeppelin/sdk'; import { InterpreterService, MessageService } from '@zeppelin/services'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts index 0258bbe8601..64cfdee30fa 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts @@ -16,24 +16,22 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { - NzButtonModule, - NzDividerModule, - NzDropDownModule, - NzFormModule, - NzGridModule, - NzIconModule, - NzInputModule, - NzNoAnimationModule, - NzPopconfirmModule, - NzPopoverModule, - NzProgressModule, - NzRadioModule, - NzSelectModule, - NzSwitchModule, - NzToolTipModule -} from 'ng-zorro-antd'; +import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor'; +import { NzNoAnimationModule } from 'ng-zorro-antd/core'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzPopoverModule } from 'ng-zorro-antd/popover'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts index eacf2da709a..846a46de1b9 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -23,7 +23,8 @@ import { } from '@angular/core'; import { copyTextToClipboard } from '@zeppelin/core'; -import { NzMessageService, NzModalService } from 'ng-zorro-antd'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { ActivatedRoute } from '@angular/router'; import { RuntimeInfos } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts index eb749c108fb..6ceaaeb5951 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts @@ -21,7 +21,8 @@ import { Output } from '@angular/core'; -import { NzMessageService, NzModalService } from 'ng-zorro-antd'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { Permissions } from '@zeppelin/interfaces'; import { SecurityService, TicketService } from '@zeppelin/services'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts index c97c48ec89a..b8ae9a7d06b 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/share.module.ts @@ -14,7 +14,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { NzInputModule } from 'ng-zorro-antd'; +import { NzInputModule } from 'ng-zorro-antd/input'; import { ElasticInputComponent } from './elastic-input/elastic-input.component'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts index 0dab7ec7221..338a43416f7 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts @@ -25,7 +25,7 @@ import { import { Subject } from 'rxjs'; import { debounceTime, takeUntil } from 'rxjs/operators'; -import { NzCheckBoxOptionInterface } from 'ng-zorro-antd'; +import { NzCheckBoxOptionInterface } from 'ng-zorro-antd/checkbox'; import { DynamicForms, DynamicFormsItem, DynamicFormsType, DynamicFormParams } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts index 4c7ef1d0ce9..a381779f5c5 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts @@ -15,17 +15,15 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { - NzButtonModule, - NzCheckboxModule, - NzDropDownModule, - NzIconModule, - NzRadioModule, - NzSelectModule, - NzSwitchModule, - NzToolTipModule -} from 'ng-zorro-antd'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; import { NzResizableModule } from 'ng-zorro-antd/resizable'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSwitchModule } from 'ng-zorro-antd/switch'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; import { VisualizationModule } from '@zeppelin/visualizations/visualization.module'; diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts index c89d287edc7..976e44b5d00 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts @@ -18,7 +18,7 @@ import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router'; import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published'; import { HeliumManagerService } from '@zeppelin/helium-manager'; import { MessageService } from '@zeppelin/services'; -import { log } from 'ng-zorro-antd'; +import { log } from 'ng-zorro-antd/core'; @Component({ selector: 'zeppelin-workspace', diff --git a/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts index 651b709019c..f965e1dd8e9 100644 --- a/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts +++ b/zeppelin-web-angular/src/app/services/ng-template-adapter.service.ts @@ -12,7 +12,7 @@ import { Injectable } from '@angular/core'; import { Ng1MigrationComponent } from '@zeppelin/share/ng1-migration/ng1-migration.component'; -import { NzModalService } from 'ng-zorro-antd'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { Observable } from 'rxjs'; export interface NgTemplateCheckResult { diff --git a/zeppelin-web-angular/src/app/services/note-action.service.ts b/zeppelin-web-angular/src/app/services/note-action.service.ts index 8a2bd102841..44e0ca8861c 100644 --- a/zeppelin-web-angular/src/app/services/note-action.service.ts +++ b/zeppelin-web-angular/src/app/services/note-action.service.ts @@ -12,7 +12,7 @@ import { Injectable } from '@angular/core'; -import { NzModalService } from 'ng-zorro-antd'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { FolderRenameComponent } from '@zeppelin/share/folder-rename/folder-rename.component'; import { NoteCreateComponent } from '@zeppelin/share/note-create/note-create.component'; diff --git a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts index 9c91b697bca..8ec7f2c36e9 100644 --- a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts +++ b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts @@ -10,7 +10,6 @@ * limitations under the License. */ -import { CommonModule } from '@angular/common'; import { Compiler, Component, @@ -20,10 +19,8 @@ import { NgModuleFactory, Type } from '@angular/core'; -import { FormsModule } from '@angular/forms'; - -import { NgZorroAntdModule } from 'ng-zorro-antd'; +import { RuntimeDynamicModuleModule } from '@zeppelin/core'; import { NgZService } from './ng-z.service'; export class DynamicTemplate { @@ -63,7 +60,7 @@ export class RuntimeCompilerService { declarations: [dynamicComponent], exports: [dynamicComponent], entryComponents: [dynamicComponent], - imports: [CommonModule, NgZorroAntdModule, FormsModule] + imports: [RuntimeDynamicModuleModule] })(class DynamicModule {}); this.compiledModule = await this.compiler.compileModuleAndAllComponentsAsync(dynamicModule); diff --git a/zeppelin-web-angular/src/app/services/ticket.service.ts b/zeppelin-web-angular/src/app/services/ticket.service.ts index 9254cdc6ee7..a23bc0d1832 100644 --- a/zeppelin-web-angular/src/app/services/ticket.service.ts +++ b/zeppelin-web-angular/src/app/services/ticket.service.ts @@ -16,7 +16,7 @@ import { Router } from '@angular/router'; import { forkJoin, BehaviorSubject, Subject } from 'rxjs'; import { map, tap } from 'rxjs/operators'; -import { NzMessageService } from 'ng-zorro-antd'; +import { NzMessageService } from 'ng-zorro-antd/message'; import { ITicket, ITicketWrapped, IZeppelinVersion } from '@zeppelin/interfaces'; import { ConfigurationsInfo } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts index 250dac36854..4b50f3be374 100644 --- a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts +++ b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts @@ -12,7 +12,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { NzModalRef } from 'ng-zorro-antd'; +import { NzModalRef } from 'ng-zorro-antd/modal'; import { MessageService } from '@zeppelin/services/message.service'; import { NoteListService } from '@zeppelin/services/note-list.service'; diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts index d9e4cc7e693..e69b89e7c84 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.ts +++ b/zeppelin-web-angular/src/app/share/header/header.component.ts @@ -12,7 +12,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { NavigationEnd, Router } from '@angular/router'; -import { NzModalService } from 'ng-zorro-antd'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; diff --git a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts index 340330e92ff..eaf32db9ee1 100644 --- a/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts +++ b/zeppelin-web-angular/src/app/share/ng1-migration/ng1-migration.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy } from '@angular/core'; import { editor, IDisposable, Range } from 'monaco-editor'; -import { NzModalRef } from 'ng-zorro-antd'; +import { NzModalRef } from 'ng-zorro-antd/modal'; import { defaultTemplateUpdaterRules, LogLevel, diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts index c9206fd1fce..5d9abb4d89e 100644 --- a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts @@ -12,7 +12,8 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { NzModalService, NzTreeNode } from 'ng-zorro-antd'; +import { NzTreeNode } from 'ng-zorro-antd/core'; +import { NzModalService } from 'ng-zorro-antd/modal'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts index 42d9a95c91b..dfa9af43b7f 100644 --- a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts @@ -12,7 +12,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { NzModalRef } from 'ng-zorro-antd'; +import { NzModalRef } from 'ng-zorro-antd/modal'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { InterpreterItem, MessageReceiveDataTypeMap, Note, OP } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts index 4e928c957af..7317b341157 100644 --- a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts @@ -14,7 +14,8 @@ import { HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { get } from 'lodash'; -import { NzModalRef, UploadFile } from 'ng-zorro-antd'; +import { NzModalRef } from 'ng-zorro-antd/modal'; +import { UploadFile } from 'ng-zorro-antd/upload'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { OP } from '@zeppelin/sdk'; diff --git a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts index 3b07b8d51b9..1413e1db315 100644 --- a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts +++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts @@ -12,7 +12,7 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; -import { NzModalRef } from 'ng-zorro-antd'; +import { NzModalRef } from 'ng-zorro-antd/modal'; import { MessageService } from '@zeppelin/services/message.service'; diff --git a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts index 601726eed30..0ec592531f2 100644 --- a/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts +++ b/zeppelin-web-angular/src/app/share/page-header/page-header.component.ts @@ -11,7 +11,7 @@ */ import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core'; -import { InputBoolean } from 'ng-zorro-antd'; +import { InputBoolean } from 'ng-zorro-antd/core'; @Component({ selector: 'zeppelin-page-header', diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts index 3f7a003b1b1..26047e4fa8a 100644 --- a/zeppelin-web-angular/src/app/share/share.module.ts +++ b/zeppelin-web-angular/src/app/share/share.module.ts @@ -15,30 +15,28 @@ import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { RouterModule } from '@angular/router'; -import { - NzAddOnModule, - NzAlertModule, - NzBadgeModule, - NzButtonModule, - NzCardModule, - NzDividerModule, - NzDropDownModule, - NzFormModule, - NzGridModule, - NzIconModule, - NzInputModule, - NzMenuModule, - NzMessageModule, - NzModalModule, - NzNotificationModule, - NzPopconfirmModule, - NzProgressModule, - NzSelectModule, - NzTabsModule, - NzToolTipModule, - NzTreeModule, - NzUploadModule -} from 'ng-zorro-antd'; +import { NzAlertModule } from 'ng-zorro-antd/alert'; +import { NzBadgeModule } from 'ng-zorro-antd/badge'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzAddOnModule } from 'ng-zorro-antd/core'; +import { NzDividerModule } from 'ng-zorro-antd/divider'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMenuModule } from 'ng-zorro-antd/menu'; +import { NzMessageModule } from 'ng-zorro-antd/message'; +import { NzModalModule } from 'ng-zorro-antd/modal'; +import { NzNotificationModule } from 'ng-zorro-antd/notification'; +import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; +import { NzProgressModule } from 'ng-zorro-antd/progress'; +import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzTabsModule } from 'ng-zorro-antd/tabs'; +import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTreeModule } from 'ng-zorro-antd/tree'; +import { NzUploadModule } from 'ng-zorro-antd/upload'; import { AboutZeppelinComponent } from '@zeppelin/share/about-zeppelin/about-zeppelin.component'; import { CodeEditorModule } from '@zeppelin/share/code-editor'; diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts index 09fa0778426..d0986315589 100644 --- a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts @@ -13,7 +13,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, OnInit, ViewChild } from '@angular/core'; import { filter, maxBy, minBy, orderBy, sumBy } from 'lodash'; -import { NzTableComponent } from 'ng-zorro-antd'; +import { NzTableComponent } from 'ng-zorro-antd/table'; import { utils, writeFile, WorkSheet } from 'xlsx'; import { TableData, Visualization, VISUALIZATION } from '@zeppelin/visualization'; diff --git a/zeppelin-web-angular/src/app/visualizations/visualization.module.ts b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts index fe2f4a18cd4..ab7221078e6 100644 --- a/zeppelin-web-angular/src/app/visualizations/visualization.module.ts +++ b/zeppelin-web-angular/src/app/visualizations/visualization.module.ts @@ -15,20 +15,18 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { - NzButtonModule, - NzCardModule, - NzCheckboxModule, - NzDropDownModule, - NzFormModule, - NzGridModule, - NzIconModule, - NzInputModule, - NzMenuModule, - NzRadioModule, - NzTableModule, - NzTagModule -} from 'ng-zorro-antd'; +import { NzButtonModule } from 'ng-zorro-antd/button'; +import { NzCardModule } from 'ng-zorro-antd/card'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; +import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzFormModule } from 'ng-zorro-antd/form'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; +import { NzMenuModule } from 'ng-zorro-antd/menu'; +import { NzRadioModule } from 'ng-zorro-antd/radio'; +import { NzTableModule } from 'ng-zorro-antd/table'; +import { NzTagModule } from 'ng-zorro-antd/tag'; import { AreaChartVisualizationComponent } from './area-chart/area-chart-visualization.component'; import { BarChartVisualizationComponent } from './bar-chart/bar-chart-visualization.component'; diff --git a/zeppelin-web-angular/tslint.json b/zeppelin-web-angular/tslint.json index 74aed2552ed..045107bdf2e 100644 --- a/zeppelin-web-angular/tslint.json +++ b/zeppelin-web-angular/tslint.json @@ -1,6 +1,7 @@ { - "rulesDirectory": ["node_modules/codelyzer"], + "rulesDirectory": ["node_modules/codelyzer", "node_modules/nz-tslint-rules"], "rules": { + "nz-secondary-entry-imports": true, "banana-in-box": true, "templates-no-negated-async": true, "no-life-cycle-call": false, From 2c8b852e19ba117dbd0fdc8718a4ea97d6f32acc Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Fri, 20 Dec 2019 16:36:26 +0800 Subject: [PATCH 15/32] [ZEPPELIN-4502] Adjust global styles and theming the visualization ### What is this PR for? Adjust global styles and theming the visualization ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4502 ### How should this be tested? Not applicable ### Screenshots (if appropriate) ![image](https://user-images.githubusercontent.com/22736418/71349913-06af2b80-25ab-11ea-9356-d160f20cf8c1.png) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3563 from hsuanxyz/feat/theme and squashes the following commits: 73271f24d [Hsuan Lee] chore: add visualization theme config 757154965 [Hsuan Lee] chore: reset the editor theme 410e0644e [Hsuan Lee] chore: adjust styles ad6fc5a52 [Hsuan Lee] feat: styling table in the HTML result 1ec33b652 [Hsuan Lee] fix: quartz url 507b2b732 [Hsuan Lee] fix: notebook cron model error c95ef6b54 [Hsuan Lee] feat: show front-end error in result df24cc074 [Hsuan Lee] feat: scroll to the paragraph when the position is moved --- zeppelin-web-angular/angular.json | 3 +- zeppelin-web-angular/package-lock.json | 21 ++- zeppelin-web-angular/package.json | 3 +- zeppelin-web-angular/src/app/app.module.ts | 4 +- .../runtime-dynamic-module.module.ts | 11 ++ .../src/app/languages/load.ts | 13 +- .../interpreter/item/item.component.less | 2 +- .../notebook-repos/item/item.component.less | 2 +- .../action-bar/action-bar.component.html | 14 +- .../action-bar/action-bar.component.ts | 1 - .../workspace/notebook/notebook.component.ts | 8 ++ .../workspace/notebook/notebook.module.ts | 4 +- .../notebook/paragraph/paragraph.component.ts | 6 + .../share/result/result.component.html | 1 + .../share/result/result.component.less | 36 +++++ .../share/result/result.component.ts | 23 ++-- .../app/pages/workspace/share/share.module.ts | 6 +- .../pages/workspace/workspace.component.ts | 2 + .../app/services/runtime-compiler.service.ts | 22 ++- .../src/app/services/shortcut.service.ts | 8 +- .../share/node-list/node-list.component.html | 2 +- .../share/node-list/node-list.component.less | 4 - .../src/app/utility/element.ts | 19 +++ .../bar-chart-visualization.component.ts | 3 + .../pivot-setting.component.html | 2 +- .../pivot-setting.component.less | 6 + .../scatter-setting.component.html | 2 +- .../scatter-setting.component.less | 6 + .../src/app/visualizations/g2.config.ts | 130 ++++++++++++++++++ .../src/styles/theme/light/theme-light.less | 4 +- 30 files changed, 307 insertions(+), 61 deletions(-) create mode 100644 zeppelin-web-angular/src/app/utility/element.ts create mode 100644 zeppelin-web-angular/src/app/visualizations/g2.config.ts diff --git a/zeppelin-web-angular/angular.json b/zeppelin-web-angular/angular.json index 37904c102f7..095c3881d31 100644 --- a/zeppelin-web-angular/angular.json +++ b/zeppelin-web-angular/angular.json @@ -72,7 +72,8 @@ "src/styles/theme/light/antd-light.less", "src/styles.less", "./node_modules/highlight.js/styles/github.css", - "./node_modules/monaco-editor/min/vs/editor/editor.main.css" + "./node_modules/monaco-editor/min/vs/editor/editor.main.css", + "./node_modules/github-markdown-css/github-markdown.css" ], "stylePreprocessorOptions": { "includePaths": [ diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index da898b09ce3..8c82716f71c 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -2844,13 +2844,10 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, - "ansi-to-html": { - "version": "0.6.12", - "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.12.tgz", - "integrity": "sha512-qBkIqLW979675mP76yB7yVkzeAWtATegdnDQ0RA3CZzknx0yUlNxMSML4xFdBfTs2GWYFQ1FELfbGbVSPzJ+LA==", - "requires": { - "entities": "^1.1.2" - } + "ansi_up": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-4.0.4.tgz", + "integrity": "sha512-vRxC8q6QY918MbehO869biJW4tiunJdjOhi5fpY6NLOliBQlZhOkKgABJKJqH+JZfb/WfjvjN1chLWI6tODerw==" }, "any-observable": { "version": "0.3.0", @@ -5538,11 +5535,6 @@ "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", "dev": true }, - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" - }, "err-code": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", @@ -6396,6 +6388,11 @@ "assert-plus": "^1.0.0" } }, + "github-markdown-css": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-3.0.1.tgz", + "integrity": "sha512-9G5CIPsHoyk5ObDsb/H4KTi23J8KE1oDd4KYU51qwqeM+lKWAiO7abpSgCkyWswgmSKBiuE7/4f8xUz7f2qAiQ==" + }, "glob": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 670c73cc2ce..9d8cafef99e 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -28,10 +28,11 @@ "@angular/router": "~8.2.10", "@antv/data-set": "^0.10.2", "@antv/g2": "^3.5.4", - "ansi-to-html": "^0.6.11", + "ansi_up": "^4.0.4", "core-js": "^2.5.4", "date-fns": "^1.30.1", "diff-match-patch": "^1.0.4", + "github-markdown-css": "^3.0.1", "highlight.js": "^9.15.8", "lodash": "^4.17.11", "mathjax": "2.7.5", diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts index 06be7f4f6f1..5f651027048 100644 --- a/zeppelin-web-angular/src/app/app.module.ts +++ b/zeppelin-web-angular/src/app/app.module.ts @@ -25,7 +25,7 @@ import { NzModalService } from 'ng-zorro-antd/modal'; import { NzNotificationService } from 'ng-zorro-antd/notification'; import { MESSAGE_INTERCEPTOR, TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; -import { loadMonacoLanguage } from '@zeppelin/languages'; +import { loadMonacoBefore } from '@zeppelin/languages'; import { TicketService } from '@zeppelin/services'; import { ShareModule } from '@zeppelin/share'; @@ -37,7 +37,7 @@ import { RUNTIME_COMPILER_PROVIDERS } from './app-runtime-compiler.providers'; import { AppComponent } from './app.component'; export const loadMonaco = () => { - loadMonacoLanguage(); + loadMonacoBefore(); }; registerLocaleData(en); diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts index d6cb44c8c2f..27d08f94a81 100644 --- a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/runtime-dynamic-module.module.ts @@ -1,3 +1,14 @@ +/* + * 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 { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; diff --git a/zeppelin-web-angular/src/app/languages/load.ts b/zeppelin-web-angular/src/app/languages/load.ts index 5dad459c888..64c617acd6e 100644 --- a/zeppelin-web-angular/src/app/languages/load.ts +++ b/zeppelin-web-angular/src/app/languages/load.ts @@ -10,10 +10,19 @@ * limitations under the License. */ -import { languages } from 'monaco-editor'; +import { editor, languages } from 'monaco-editor'; import { conf as ScalaConf, language as ScalaLanguage } from './scala'; -export const loadMonacoLanguage = () => { +export const loadMonacoBefore = () => { + editor.defineTheme('zeppelin-theme', { + base: 'vs', + inherit: true, + rules: [], + colors: { + 'editor.lineHighlightBackground': '#0000FF10' + } + }); + editor.setTheme('zeppelin-theme'); languages.register({ id: 'scala' }); languages.setMonarchTokensProvider('scala', ScalaLanguage); languages.setLanguageConfiguration('scala', ScalaConf); diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less index 856506e92f2..746967dc88f 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.less @@ -19,7 +19,7 @@ ::ng-deep .interpreter-item { &.edit { - background: @orange-1; + //background: @orange-1; } .ant-card-body { margin-top: -@card-padding-base; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less index bc6d2805eb8..7e242390dcf 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.less @@ -20,7 +20,7 @@ ::ng-deep .repo-item { &.edit { - background: @orange-1; + //background: @orange-1; } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html index 0238f171aca..1da21e63a63 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html @@ -125,11 +125,9 @@ (click)="toggleExtension('revisions')"> - - - +
    • @@ -188,7 +186,8 @@
      Run note with cron scheduler. Either choose from preset or write your own - + cron expression . @@ -226,7 +225,8 @@ - diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts index 994acc11cb4..9ec5dedb631 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts @@ -69,7 +69,6 @@ export class NotebookActionBarComponent extends MessageListenersManager implemen { name: '12h', value: '0 0 0/12 * * ?' }, { name: '1d', value: '0 0 0 * * ?' } ]; - updateNoteName(name: string) { const trimmedNewName = name.trim(); if (trimmedNewName.length > 0 && this.note.name !== trimmedNewName) { diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index e0c17a168fb..404fc288954 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -36,6 +36,7 @@ import { TicketService } from '@zeppelin/services'; +import { scrollIntoViewIfNeeded } from '@zeppelin/utility/element'; import { NotebookParagraphComponent } from './paragraph/paragraph.component'; @Component({ @@ -151,7 +152,14 @@ export class NotebookComponent extends MessageListenersManager implements OnInit if (movedPara) { const listOfRestPara = this.note.paragraphs.filter(p => p.id !== data.id); this.note.paragraphs = [...listOfRestPara.slice(0, data.index), movedPara, ...listOfRestPara.slice(data.index)]; + const paragraphComponent = this.listOfNotebookParagraphComponent.find(e => e.paragraph.id === data.id); this.cdr.markForCheck(); + if (paragraphComponent) { + // Call when next tick + setTimeout(() => { + scrollIntoViewIfNeeded(paragraphComponent.getElement()); + }); + } } } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts index 64cfdee30fa..4b71d3d8ac8 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts @@ -45,6 +45,7 @@ import { NotebookParagraphProgressComponent } from './paragraph/progress/progres import { NotebookPermissionsComponent } from './permissions/permissions.component'; import { NotebookRevisionsComparatorComponent } from './revisions-comparator/revisions-comparator.component'; +import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; import { WorkspaceShareModule } from '../../workspace/share/share.module'; import { NotebookActionBarComponent } from './action-bar/action-bar.component'; import { NotebookRoutingModule } from './notebook-routing.module'; @@ -90,7 +91,8 @@ import { NotebookShareModule } from './share/share.module'; NzGridModule, NzRadioModule, DragDropModule, - NzCodeEditorModule + NzCodeEditorModule, + NzCheckboxModule ] }) export class NotebookModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index 246d09e7aad..ad9691e9ab6 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -516,9 +516,11 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, this.commitParagraph(); break; case ParagraphActions.MoveToUp: + event.preventDefault(); this.moveUpParagraph(); break; case ParagraphActions.MoveToDown: + event.preventDefault(); this.moveDownParagraph(); break; case ParagraphActions.SwitchEnable: @@ -622,6 +624,10 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, } } + getElement(): HTMLElement { + return this.host && this.host.nativeElement; + } + ngOnDestroy(): void { super.ngOnDestroy(); } diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html index 0b246b0efbf..cb8369f273e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html @@ -68,6 +68,7 @@
      img
      +
      {{frontEndError}}
      diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less index f1970729ab9..37f0dcb16a8 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.less @@ -29,6 +29,11 @@ } ::ng-deep { + + .visualization-selector .ant-radio-button-wrapper { + padding: 0 10px; + } + .inner-html, .text-plain { overflow: auto; @@ -42,6 +47,37 @@ height: auto; width: auto; } + + table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: @text-color; + table-layout: fixed; + } + thead { + color: @table-header-color; + border-bottom: 2px @border-style-base fade(@black, 65%); + vertical-align: bottom; + } + tr, th, td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; + } + th { + font-weight: bold; + } + tbody tr:nth-child(odd) { + background: darken(@table-header-bg, 3%); + } + tbody tr:hover { + background: @table-row-hover-bg; + } } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts index 86d94cce9a0..c8b75b903a6 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts @@ -29,7 +29,7 @@ import { DomSanitizer, SafeHtml, SafeUrl } from '@angular/platform-browser'; import { Subject, Subscription } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import * as Convert from 'ansi-to-html'; +import { default as AnsiUp } from 'ansi_up'; import * as hljs from 'highlight.js'; import { NzResizeEvent } from 'ng-zorro-antd/resizable'; import { utils, writeFile, WorkSheet, WritingOptions } from 'xlsx'; @@ -206,6 +206,7 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, } renderDefaultDisplay() { + this.frontEndError = ''; switch (this.result.type) { case DatasetType.TABLE: this.renderGraph(); @@ -240,22 +241,22 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, } renderAngular(): void { - try { - this.runtimeCompilerService.createAndCompileTemplate(this.id, this.result.data).then(data => { + this.runtimeCompilerService + .createAndCompileTemplate(this.id, this.result.data) + .then(data => { this.angularComponent = data; - // this.angularComponent.moduleFactory + this.cdr.markForCheck(); + }) + .catch(error => { + this.angularComponent = null; + this.frontEndError = error.message; this.cdr.markForCheck(); }); - } catch (e) { - this.frontEndError = e.message; - console.log(e); - } } renderText(): void { - // tslint:disable-next-line:no-any - const convert: any = new Convert(); - this.plainText = this.sanitizer.bypassSecurityTrustHtml(convert.toHtml(this.result.data)); + const ansiUp = new AnsiUp(); + this.plainText = this.sanitizer.bypassSecurityTrustHtml(ansiUp.ansi_to_html(this.result.data)); } renderImg(): void { diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts index a381779f5c5..37bebf3ab83 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts @@ -28,6 +28,8 @@ import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; import { VisualizationModule } from '@zeppelin/visualizations/visualization.module'; +import { NzGridModule } from 'ng-zorro-antd/grid'; +import { NzInputModule } from 'ng-zorro-antd/input'; import { NotebookParagraphDynamicFormsComponent } from './dynamic-forms/dynamic-forms.component'; import { NotebookParagraphResultComponent } from './result/result.component'; @@ -48,7 +50,9 @@ import { NotebookParagraphResultComponent } from './result/result.component'; NzIconModule, NzCheckboxModule, NzSelectModule, - NzSwitchModule + NzSwitchModule, + NzInputModule, + NzGridModule ] }) export class WorkspaceShareModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts index 976e44b5d00..410ef17c7f3 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts @@ -18,6 +18,7 @@ import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router'; import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published'; import { HeliumManagerService } from '@zeppelin/helium-manager'; import { MessageService } from '@zeppelin/services'; +import { setTheme } from '@zeppelin/visualizations/g2.config'; import { log } from 'ng-zorro-antd/core'; @Component({ @@ -47,6 +48,7 @@ export class WorkspaceComponent implements OnInit, OnDestroy { this.websocketConnected = data; this.cdr.markForCheck(); }); + setTheme(); this.heliumManagerService.initPackages(); } diff --git a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts index 8ec7f2c36e9..f7f6fc42664 100644 --- a/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts +++ b/zeppelin-web-angular/src/app/services/runtime-compiler.service.ts @@ -11,15 +11,17 @@ */ import { + ChangeDetectionStrategy, Compiler, Component, Injectable, - ModuleWithComponentFactories, NgModule, NgModuleFactory, + NO_ERRORS_SCHEMA, Type } from '@angular/core'; +import { CompileDirectiveMetadata, HtmlParser, TemplateParser } from '@angular/compiler'; import { RuntimeDynamicModuleModule } from '@zeppelin/core'; import { NgZService } from './ng-z.service'; @@ -33,16 +35,17 @@ export class DynamicTemplate { ) {} } +export class DynamicTemplateError { + constructor(public message: string) {} +} + @Injectable({ providedIn: 'root' }) export class RuntimeCompilerService { - // tslint:disable-next-line:no-any - private compiledModule?: ModuleWithComponentFactories; - public async createAndCompileTemplate(paragraphId: string, template: string): Promise { const ngZService = this.ngZService; - const dynamicComponent = Component({ template: template })( + const dynamicComponent = Component({ template: template, selector: `dynamic-${paragraphId}` })( class DynamicTemplateComponent { z = { set: (key: string, value, id: string) => ngZService.setContextValue(key, value, id), @@ -63,8 +66,13 @@ export class RuntimeCompilerService { imports: [RuntimeDynamicModuleModule] })(class DynamicModule {}); - this.compiledModule = await this.compiler.compileModuleAndAllComponentsAsync(dynamicModule); - return new DynamicTemplate(template, dynamicComponent, this.compiledModule.ngModuleFactory); + try { + this.compiler.clearCache(); + const compiledModule = await this.compiler.compileModuleAndAllComponentsAsync(dynamicModule); + return new DynamicTemplate(template, dynamicComponent, compiledModule.ngModuleFactory); + } catch (e) { + throw new DynamicTemplateError(`${e}`); + } } constructor(private compiler: Compiler, private ngZService: NgZService) {} diff --git a/zeppelin-web-angular/src/app/services/shortcut.service.ts b/zeppelin-web-angular/src/app/services/shortcut.service.ts index 4b2a62627a6..5bc9a2a2fcd 100644 --- a/zeppelin-web-angular/src/app/services/shortcut.service.ts +++ b/zeppelin-web-angular/src/app/services/shortcut.service.ts @@ -44,10 +44,10 @@ export const ShortcutsMap = { // Need register special character `≠` in MacOS [ParagraphActions.IncreaseWidth]: ['alt.ctrlCmd.+', 'alt.ctrlCmd.≠'], [ParagraphActions.Delete]: 'shift.delete', - [ParagraphActions.MoveToUp]: ['ctrlCmd.k', 'ctrlCmd.arrowup'], - [ParagraphActions.MoveToDown]: ['ctrlCmd.j', 'ctrlCmd.arrowdown'], - [ParagraphActions.SelectAbove]: ['k', 'arrowup'], - [ParagraphActions.SelectBelow]: ['j', 'arrowdown'], + [ParagraphActions.MoveToUp]: ['ctrlCmd.k', 'ctrlCmd.arrowup', 'ctrlCmd.arrowleft'], + [ParagraphActions.MoveToDown]: ['ctrlCmd.j', 'ctrlCmd.arrowdown', 'ctrlCmd.arrowright'], + [ParagraphActions.SelectAbove]: ['k', 'arrowup', 'arrowleft'], + [ParagraphActions.SelectBelow]: ['j', 'arrowdown', 'arrowright'], [ParagraphActions.SwitchLineNumber]: 'l', [ParagraphActions.SwitchTitleShow]: 't', [ParagraphActions.SwitchOutputShow]: 'o', diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.html b/zeppelin-web-angular/src/app/share/node-list/node-list.component.html index 70be6910499..7800443217f 100644 --- a/zeppelin-web-angular/src/app/share/node-list/node-list.component.html +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.html @@ -72,7 +72,7 @@

      - + {{ node.title }} diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.less b/zeppelin-web-angular/src/app/share/node-list/node-list.component.less index aec40c15ccf..ea197e40200 100644 --- a/zeppelin-web-angular/src/app/share/node-list/node-list.component.less +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.less @@ -48,10 +48,6 @@ filter: grayscale(1); } - i { - margin-right: 6px; - } - .operation { margin-left: 12px; diff --git a/zeppelin-web-angular/src/app/utility/element.ts b/zeppelin-web-angular/src/app/utility/element.ts new file mode 100644 index 00000000000..cdae6de0045 --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/element.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ + +export function scrollIntoViewIfNeeded(element: HTMLElement, center = true): void { + // tslint:disable-next-line:no-any + if (element && typeof (element as any).scrollIntoViewIfNeeded === 'function') { + // tslint:disable-next-line:no-any + (element as any).scrollIntoViewIfNeeded(center); + } +} diff --git a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts index 82ed55f0dcf..22944451cb2 100644 --- a/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts +++ b/zeppelin-web-angular/src/app/visualizations/bar-chart/bar-chart-visualization.component.ts @@ -83,6 +83,9 @@ export class BarChartVisualizationComponent extends G2VisualizationComponentBase const key = this.getKey(); this.setScale(); + this.chart.tooltip({ + shared: false + }); if (get(this.config.setting, 'multiBarChart.stacked', false)) { this.chart .intervalStack() diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html index 2a91d7beccd..fb1497f43db 100644 --- a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.html @@ -10,7 +10,7 @@ ~ limitations under the License. --> - +
      - +
      Date: Tue, 24 Dec 2019 10:06:54 +0800 Subject: [PATCH 16/32] [ZEPPELIN-4503] Support note scope dynamic forms ### What is this PR for? Support note scope dynamic forms ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4503 ### How should this be tested? Not applicable ### Screenshots (if appropriate) ![Kapture 2019-12-24 at 10 05 11](https://user-images.githubusercontent.com/22736418/71389013-a3b6a680-2635-11ea-8439-a4b81cc3277e.gif) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3565 from hsuanxyz/feat/note-dynamic-forms and squashes the following commits: 342aecfd8 [Hsuan Lee] chore: add component modules in share b8208937c [Hsuan Lee] feat: support note scope dynamaic forms --- .../interfaces/message-notebook.interface.ts | 1 + .../interfaces/message-paragraph.interface.ts | 1 + .../note-form-block.component.html | 25 ++++++++ .../note-form-block.component.less | 27 ++++++++ .../note-form-block.component.ts | 43 +++++++++++++ .../notebook/notebook.component.html | 8 +++ .../workspace/notebook/notebook.component.ts | 42 ++++++++++++- .../workspace/notebook/notebook.module.ts | 4 +- .../elastic-input.component.html | 2 +- .../elastic-input/elastic-input.component.ts | 3 +- .../dynamic-forms.component.html | 62 +++++++++++-------- .../dynamic-forms.component.less | 24 ++++++- .../dynamic-forms/dynamic-forms.component.ts | 6 ++ .../app/pages/workspace/share/share.module.ts | 8 +-- 14 files changed, 222 insertions(+), 34 deletions(-) create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less create mode 100644 zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts index f7b22de6daf..649a312561a 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts @@ -197,6 +197,7 @@ export interface NotesInfoItem extends ID { export interface NoteConfig { cron?: string; releaseresource: boolean; + noteFormTitle?: string; cronExecutingRoles?: string; cronExecutingUser?: string; isZeppelinNotebookCronEnable: boolean; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts index bcc01995892..2e04b225adb 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts @@ -23,6 +23,7 @@ export interface DynamicFormsItem { defaultValue: string | string[]; hidden: boolean; name: string; + displayName?: string; type: DynamicFormsType; argument?: string; options?: Array<{ value: string; displayName?: string }>; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html new file mode 100644 index 00000000000..2ca58518f71 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.html @@ -0,0 +1,25 @@ + +
      + + + +
      diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less new file mode 100644 index 00000000000..896b6f8dabf --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.less @@ -0,0 +1,27 @@ +/* + * 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 "theme-mixin"; + +:host { + display: block; + padding: 0 4px; +} + +.themeMixin({ + .forms-wrap { + background: @component-background; + border: 1px solid @border-color-split; + box-shadow: @card-shadow; + padding: 12px; + position: relative; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts new file mode 100644 index 00000000000..9eb0b721403 --- /dev/null +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts @@ -0,0 +1,43 @@ +/* + * 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 { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { DynamicForms, DynamicFormParams } from '@zeppelin/sdk'; + +@Component({ + selector: 'zeppelin-note-form-block', + templateUrl: './note-form-block.component.html', + styleUrls: ['./note-form-block.component.less'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class NoteFormBlockComponent implements OnInit { + @Input() noteTitle: string; + @Input() formDefs: DynamicForms; + @Input() paramDefs: DynamicFormParams; + @Output() readonly noteTitleChange = new EventEmitter(); + @Output() readonly noteFormChange = new EventEmitter(); + @Output() readonly noteFormNameRemove = new EventEmitter(); + constructor() {} + + ngOnInit() {} + + onFormRemove({ name }) { + this.noteFormNameRemove.emit(name); + } + + onFormChange() { + this.noteFormChange.emit(this.paramDefs); + } + + setTitle(title: string) { + this.noteTitleChange.emit(title); + } +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html index c447a59c39d..d9574db30cd 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -34,6 +34,14 @@
      + +
      p.setEditorHide(editorHide)); } + onNoteFormChange(noteParams: DynamicFormParams) { + this.messageService.saveNoteForms({ + noteParams, + id: this.note.id + }); + } + + onFormNameRemove(formName: string) { + this.messageService.removeNoteForms(this.note, formName); + } + + onNoteTitleChange(noteFormTitle: string) { + this.messageService.updateNote(this.note.id, this.note.name, { + ...this.note.config, + noteFormTitle + }); + } + + setNoteFormsStatus() { + this.isShowNoteForms = this.note && this.note.noteForms && Object.keys(this.note.noteForms).length !== 0; + this.cdr.markForCheck(); + } + constructor( private activatedRoute: ActivatedRoute, public messageService: MessageService, diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts index 4b71d3d8ac8..49a6230e22c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts @@ -48,6 +48,7 @@ import { NotebookRevisionsComparatorComponent } from './revisions-comparator/rev import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; import { WorkspaceShareModule } from '../../workspace/share/share.module'; import { NotebookActionBarComponent } from './action-bar/action-bar.component'; +import { NoteFormBlockComponent } from './note-form-block/note-form-block.component'; import { NotebookRoutingModule } from './notebook-routing.module'; import { NotebookComponent } from './notebook.component'; import { NotebookShareModule } from './share/share.module'; @@ -64,7 +65,8 @@ import { NotebookShareModule } from './share/share.module'; NotebookParagraphCodeEditorComponent, NotebookParagraphProgressComponent, NotebookParagraphFooterComponent, - NotebookParagraphControlComponent + NotebookParagraphControlComponent, + NoteFormBlockComponent ], imports: [ CommonModule, diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html index c605d28771b..aa7b5e777b5 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html @@ -19,5 +19,5 @@ (keydown.esc)="cancelEdit()" (keydown.enter)="setEditorState(false)" (input)="updateInputWidth()"> -

      {{value || 'Untitled'}}

      +

      {{value || defaultTitle}}

      diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts index ef4dce4e988..2057a875cf1 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts @@ -33,6 +33,7 @@ export class ElasticInputComponent implements OnChanges { @Input() value: string; @Input() readonly = false; @Input() min = false; + @Input() defaultTitle = 'Untitled'; @Output() readonly valueUpdate = new EventEmitter(); @ViewChild('inputElement', { read: ElementRef, static: false }) inputElement: ElementRef; @ViewChild('pElement', { read: ElementRef, static: false }) pElement: ElementRef; @@ -47,7 +48,7 @@ export class ElasticInputComponent implements OnChanges { updateValue(value: string) { const trimmedNewName = value.trim(); - if (trimmedNewName.length > 0 && this.value !== trimmedNewName) { + if (typeof value === 'string') { this.editValue = trimmedNewName; } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html index 3a4cfdd5ff0..330b3e82220 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.html @@ -20,32 +20,44 @@ nzLg="8" nzMd="12" nzSm="24"> - - - - + +
      + + - - - - - - + + + + + + + + + +
      +

      diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less index 060b2f8485d..a9a4b889420 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.less @@ -10,15 +10,37 @@ * limitations under the License. */ +@import "theme-mixin"; + :host { display: block; +} + +.themeMixin({ + .control-wrap { + display: flex; + } .form-item { margin-bottom: 24px; + .item-label { + font-weight: 700; + } nz-select { width: 100%; } ::ng-deep .ant-checkbox-wrapper { margin-left: 0; + line-height: 32px; + } + &:hover { + .remove-button { + color: @text-color-danger; + } + } + .remove-button { + margin: 0 4px; + transition: color ease-in-out .3s; + color: @text-color-secondary; } } -} +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts index 338a43416f7..b6eb9f9bb73 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/dynamic-forms/dynamic-forms.component.ts @@ -42,7 +42,9 @@ export class NotebookParagraphDynamicFormsComponent implements OnInit, OnChanges @Input() paramDefs: DynamicFormParams; @Input() runOnChange = false; @Input() disable = false; + @Input() removable = false; @Output() readonly formChange = new EventEmitter(); + @Output() readonly formRemove = new EventEmitter(); formChange$ = new Subject(); forms: DynamicFormsItem[] = []; @@ -97,6 +99,10 @@ export class NotebookParagraphDynamicFormsComponent implements OnInit, OnChanges } } + remove(item: DynamicFormsItem) { + this.formRemove.emit(item); + } + constructor() {} ngOnInit() { diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts index 37bebf3ab83..dfc2c4c5bae 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts @@ -18,7 +18,9 @@ import { FormsModule } from '@angular/forms'; import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; +import { NzGridModule } from 'ng-zorro-antd/grid'; import { NzIconModule } from 'ng-zorro-antd/icon'; +import { NzInputModule } from 'ng-zorro-antd/input'; import { NzRadioModule } from 'ng-zorro-antd/radio'; import { NzResizableModule } from 'ng-zorro-antd/resizable'; import { NzSelectModule } from 'ng-zorro-antd/select'; @@ -28,8 +30,6 @@ import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; import { VisualizationModule } from '@zeppelin/visualizations/visualization.module'; -import { NzGridModule } from 'ng-zorro-antd/grid'; -import { NzInputModule } from 'ng-zorro-antd/input'; import { NotebookParagraphDynamicFormsComponent } from './dynamic-forms/dynamic-forms.component'; import { NotebookParagraphResultComponent } from './result/result.component'; @@ -51,8 +51,8 @@ import { NotebookParagraphResultComponent } from './result/result.component'; NzCheckboxModule, NzSelectModule, NzSwitchModule, - NzInputModule, - NzGridModule + NzGridModule, + NzInputModule ] }) export class WorkspaceShareModule {} From 52392bf1e62a7008a5b65eb8054e94ceba4b357c Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Fri, 27 Dec 2019 11:06:20 +0800 Subject: [PATCH 17/32] [ZEPPELIN-4516] Fix pie chart does not color by key ### What is this PR for? Fix pie chart does not color by key ### What type of PR is it? [Bug Fix] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4516 ### How should this be tested? N/A ### Screenshots (if appropriate) ![Kapture 2019-12-27 at 11 19 06](https://user-images.githubusercontent.com/22736418/71499297-ceedff80-289a-11ea-809f-1d2e0a30776f.gif) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3574 from hsuanxyz/fix/pie-chart and squashes the following commits: 1ca2dc935 [Hsuan Lee] fix: fix the pie chart's color --- .../src/pivot-transformation.ts | 49 +++++++++++++++---- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts index cade722cd81..963cc48f9fa 100644 --- a/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/pivot-transformation.ts @@ -16,7 +16,6 @@ import { get } from 'lodash'; import { TableData } from './table-data'; import { Transformation } from './transformation'; -// tslint:disable-next-line:no-any export class PivotTransformation extends Transformation { constructor(config) { super(config); @@ -87,6 +86,8 @@ export class PivotTransformation extends Transformation { let groups = []; let values = []; let aggregates = []; + + // set values from config if (config.mode !== 'scatterChart') { keys = config.keys.map(e => e.name); groups = config.groups.map(e => e.name); @@ -101,6 +102,7 @@ export class PivotTransformation extends Transformation { groups = group ? [group] : []; } + // try coercion to number type dv.transform({ type: 'map', callback: row => { @@ -114,7 +116,10 @@ export class PivotTransformation extends Transformation { } }); + // not applicable with type scatter chart if (config.mode !== 'scatterChart') { + + // aggregate values dv.transform({ type: 'aggregate', fields: config.values.map(v => v.name), @@ -123,19 +128,36 @@ export class PivotTransformation extends Transformation { groupBy: [...keys, ...groups] }); - // dv.transform({ - // type: 'fill-rows', - // groupBy: groups, - // orderBy: keys, - // fillBy: 'order' - // }); - + // fill the rows to keep the charts is continuity dv.transform({ type: 'fill-rows', groupBy: [...keys, ...groups], fillBy: 'group' }); + /** + * fill the field to keep the charts is continuity + * + * before + * ``` + * [ + * { x: 0, y: 1 }, + * { x: 0, y: 2 }, + * { x: 0, y: 3 }, + * { x: 0 } + * ] + * ``` + * after + * ``` + * [ + * { x: 0, y: 1 }, + * { x: 0, y: 2 }, + * { x: 0, y: 3 }, + * { x: 0, y: 0 } + * // ^^^^^ filled this + * ] + * ``` + */ config.values .map(v => `${v.name}(${v.aggr})`) .forEach(field => { @@ -165,9 +187,17 @@ export class PivotTransformation extends Transformation { Object.keys(dv.rows).forEach(groupKey => { const groupName = groupKey.replace(/^_/, ''); dv.rows[groupKey].forEach(row => { + const getKey = () => { + if (config.mode !== 'pieChart') { + return groupName ? `${row.__key__}.${groupName}` : row.__key__ + } else { + const keyName = keys.map(k => row[k]).join('.'); + return groupName ? `${keyName}.${groupName}` : keyName; + } + }; groupsData.push({ ...row, - __key__: groupName ? `${row.__key__}.${groupName}` : row.__key__ + __key__: getKey() }); }); }); @@ -177,6 +207,7 @@ export class PivotTransformation extends Transformation { dv.origin.findIndex(o => o[firstKey] === a[firstKey]) - dv.origin.findIndex(o => o[firstKey] === b[firstKey]) ); + console.log(groupsData); dv = ds .createView({ state: { From 6ddc0c685f9c684c3b79b803cf238266bfd0a669 Mon Sep 17 00:00:00 2001 From: fdai Date: Tue, 31 Dec 2019 17:25:14 -0800 Subject: [PATCH 18/32] [ZEPPELIN-4515] Have Jetty Server support multiple wars ### What is this PR for? We have a new UI with version angular 8, which will be retiring the old angularjs. both of the angular frameworks may need to co-exist for a while until the new UI is stable. Have the Jetty server support multiple wars with different port (8080 and 9090) ### What type of PR is it? [Feature ] ### Todos retire angularJS completely in the future. ### What is the Jira issue? * [ZEPPELIN-4515](https://issues.apache.org/jira/browse/ZEPPELIN-4515) Have Jetty Server support multiple wars Add multiple war support for the Zeppelin Server. two ports (default is 8080 and 9090) will be living for a while until we are comfortable with the new UI. ### How should this be tested? The default port for new UI is 9090, testing via http://localhost:9090 ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? **No** * Is there breaking changes for older versions? **No** * Does this needs documentation? **No** Author: fdai Closes #3571 from fred521/add_angular_to_jetty and squashes the following commits: 196547605 [fdai] add next context path 93e2a4fdc [fdai] clean the code 8606ce064 [fdai] use one port two support multiple wars in jetty f08602e20 [fdai] remove unrelated notebook 0f9c10367 [fdai] add angular support for jetty --- bin/common.sh | 12 ++- bin/zeppelin-daemon.sh | 1 + bin/zeppelin.sh | 1 + zeppelin-distribution/pom.xml | 6 ++ .../src/assemble/distribution.xml | 4 +- .../zeppelin/conf/ZeppelinConfiguration.java | 1 + .../zeppelin/server/ZeppelinServer.java | 92 ++++++++++--------- .../zeppelin/rest/AbstractTestRestApi.java | 3 + zeppelin-web-angular/package.json | 2 +- zeppelin-web-angular/pom.xml | 2 +- 10 files changed, 74 insertions(+), 50 deletions(-) diff --git a/bin/common.sh b/bin/common.sh index 0ebae660907..4e86ce94948 100644 --- a/bin/common.sh +++ b/bin/common.sh @@ -44,7 +44,15 @@ if [[ -z "${ZEPPELIN_WAR}" ]]; then if [[ -d "${ZEPPELIN_HOME}/zeppelin-web/dist" ]]; then export ZEPPELIN_WAR="${ZEPPELIN_HOME}/zeppelin-web/dist" else - export ZEPPELIN_WAR=$(find -L "${ZEPPELIN_HOME}" -name "zeppelin-web*.war") + export ZEPPELIN_WAR=$(find -L "${ZEPPELIN_HOME}" -name "zeppelin-web-[0-9]*.war") + fi +fi + +if [[ -z "${ZEPPELIN_ANGULAR_WAR}" ]]; then + if [[ -d "${ZEPPELIN_HOME}/zeppelin-web/dist" ]]; then + export ZEPPELIN_ANGULAR_WAR="${ZEPPELIN_HOME}/zeppelin-web-angular/dist/zeppelin" + else + export ZEPPELIN_ANGULAR_WAR=$(find -L "${ZEPPELIN_HOME}" -name "zeppelin-web-angular*.war") fi fi @@ -102,7 +110,7 @@ function getZeppelinVersion(){ exit 0 } -# Text encoding for +# Text encoding for # read/write job into files, # receiving/displaying query/result. if [[ -z "${ZEPPELIN_ENCODING}" ]]; then diff --git a/bin/zeppelin-daemon.sh b/bin/zeppelin-daemon.sh index e8988497513..0ce9808e2d8 100755 --- a/bin/zeppelin-daemon.sh +++ b/bin/zeppelin-daemon.sh @@ -81,6 +81,7 @@ addJarInDir "${ZEPPELIN_HOME}/zeppelin-interpreter/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-zengine/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-server/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-web/target/lib" +addJarInDir "${ZEPPELIN_HOME}/zeppelin-web-angular/target/lib" CLASSPATH+=":${ZEPPELIN_CLASSPATH}" diff --git a/bin/zeppelin.sh b/bin/zeppelin.sh index a13f9db977d..5509e4f2f54 100755 --- a/bin/zeppelin.sh +++ b/bin/zeppelin.sh @@ -70,6 +70,7 @@ addJarInDir "${ZEPPELIN_HOME}/zeppelin-interpreter/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-zengine/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-server/target/lib" addJarInDir "${ZEPPELIN_HOME}/zeppelin-web/target/lib" +addJarInDir "${ZEPPELIN_HOME}/zeppelin-web-angular/target/lib" ZEPPELIN_CLASSPATH="$CLASSPATH:$ZEPPELIN_CLASSPATH" diff --git a/zeppelin-distribution/pom.xml b/zeppelin-distribution/pom.xml index 271067060c1..380e7a2f719 100644 --- a/zeppelin-distribution/pom.xml +++ b/zeppelin-distribution/pom.xml @@ -85,6 +85,12 @@ ${project.version} war + + ${project.groupId} + zeppelin-web-angular + ${project.version} + war + diff --git a/zeppelin-distribution/src/assemble/distribution.xml b/zeppelin-distribution/src/assemble/distribution.xml index 0c5e8b64433..0b18b4ae128 100644 --- a/zeppelin-distribution/src/assemble/distribution.xml +++ b/zeppelin-distribution/src/assemble/distribution.xml @@ -26,7 +26,7 @@ true zeppelin-${project.version} - + ${project.groupId}:zeppelin-web + ${project.groupId}:zeppelin-web-angular false false @@ -42,6 +43,7 @@ /lib ${project.groupId}:zeppelin-web + ${project.groupId}:zeppelin-web-angular false true diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java index 2a6e0bbbf2e..a6123ec661b 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java @@ -812,6 +812,7 @@ public enum ConfVars { ZEPPELIN_SSL_TRUSTSTORE_TYPE("zeppelin.ssl.truststore.type", null), ZEPPELIN_SSL_TRUSTSTORE_PASSWORD("zeppelin.ssl.truststore.password", null), ZEPPELIN_WAR("zeppelin.war", "zeppelin-web/dist"), + ZEPPELIN_ANGULAR_WAR("zeppelin.angular.war", "zeppelin-web-angular/dist"), ZEPPELIN_WAR_TEMPDIR("zeppelin.war.tempdir", "webapps"), ZEPPELIN_INTERPRETER_JSON("zeppelin.interpreter.setting", "interpreter-setting.json"), diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java index f9d8e8b6262..966f5b553aa 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java @@ -97,6 +97,7 @@ /** Main class of Zeppelin. */ public class ZeppelinServer extends ResourceConfig { private static final Logger LOG = LoggerFactory.getLogger(ZeppelinServer.class); + private static final String WEB_APP_CONTEXT_NEXT = "/next"; public static Server jettyWebServer; public static ServiceLocator sharedServiceLocator; @@ -119,9 +120,6 @@ public static void main(String[] args) throws InterruptedException { ContextHandlerCollection contexts = new ContextHandlerCollection(); jettyWebServer.setHandler(contexts); - // Web UI - final WebAppContext webApp = setupWebAppContext(contexts, conf); - sharedServiceLocator = ServiceLocatorFactory.getInstance().create("shared-locator"); ServiceLocatorUtilities.enableImmediateScope(sharedServiceLocator); ServiceLocatorUtilities.addClasses(sharedServiceLocator, @@ -180,25 +178,12 @@ protected void configure() { } }); - webApp.addEventListener( - new ServletContextListener() { - @Override - public void contextInitialized(ServletContextEvent servletContextEvent) { - servletContextEvent - .getServletContext() - .setAttribute(ServletProperties.SERVICE_LOCATOR, sharedServiceLocator); - } - - @Override - public void contextDestroyed(ServletContextEvent servletContextEvent) {} - }); - - // Create `ZeppelinServer` using reflection and setup REST Api - setupRestApiContextHandler(webApp, conf); - - // Notebook server - setupNotebookServer(webApp, conf, sharedServiceLocator); + // Multiple Web UI + final WebAppContext defaultWebApp = setupWebAppContext(contexts, conf, conf.getString(ConfVars.ZEPPELIN_WAR), conf.getServerContextPath()); + final WebAppContext nextWebApp = setupWebAppContext(contexts, conf, conf.getString(ConfVars.ZEPPELIN_ANGULAR_WAR), WEB_APP_CONTEXT_NEXT); + initWebApp(defaultWebApp); + initWebApp(nextWebApp); // Cluster Manager Server setupClusterManagerServer(sharedServiceLocator); @@ -304,14 +289,18 @@ private static Server setupJettyServer(ZeppelinConfiguration conf) { conf.getInt(ConfVars.ZEPPELIN_SERVER_JETTY_THREAD_POOL_MIN), conf.getInt(ConfVars.ZEPPELIN_SERVER_JETTY_THREAD_POOL_TIMEOUT)); final Server server = new Server(threadPool); - ServerConnector connector; + initServerConnector(server, conf.getServerPort(), conf.getServerSslPort()); + return server; + } + private static void initServerConnector(Server server, int port, int sslPort) { + ServerConnector connector; HttpConfiguration httpConfig = new HttpConfiguration(); httpConfig.addCustomizer(new ForwardedRequestCustomizer()); if (conf.useSsl()) { - LOG.debug("Enabling SSL for Zeppelin Server on port " + conf.getServerSslPort()); + LOG.debug("Enabling SSL for Zeppelin Server on port " + sslPort); httpConfig.setSecureScheme("https"); - httpConfig.setSecurePort(conf.getServerSslPort()); + httpConfig.setSecurePort(sslPort); httpConfig.setOutputBufferSize(32768); httpConfig.setResponseHeaderSize(8192); httpConfig.setSendServerVersion(true); @@ -321,28 +310,20 @@ private static Server setupJettyServer(ZeppelinConfiguration conf) { httpsConfig.addCustomizer(src); connector = - new ServerConnector( - server, - new SslConnectionFactory(getSslContextFactory(conf), HttpVersion.HTTP_1_1.asString()), - new HttpConnectionFactory(httpsConfig)); + new ServerConnector( + server, + new SslConnectionFactory(getSslContextFactory(conf), HttpVersion.HTTP_1_1.asString()), + new HttpConnectionFactory(httpsConfig)); } else { connector = new ServerConnector(server, new HttpConnectionFactory(httpConfig)); + connector.setPort(port); } - configureRequestHeaderSize(conf, connector); // Set some timeout options to make debugging easier. int timeout = 1000 * 30; connector.setIdleTimeout(timeout); connector.setHost(conf.getServerAddress()); - if (conf.useSsl()) { - connector.setPort(conf.getServerSslPort()); - } else { - connector.setPort(conf.getServerPort()); - } - server.addConnector(connector); - - return server; } private static void configureRequestHeaderSize( @@ -437,19 +418,20 @@ private static void setupRestApiContextHandler(WebAppContext webapp, ZeppelinCon } private static WebAppContext setupWebAppContext( - ContextHandlerCollection contexts, ZeppelinConfiguration conf) { + ContextHandlerCollection contexts, ZeppelinConfiguration conf, String warPath, String contextPath) { WebAppContext webApp = new WebAppContext(); - webApp.setContextPath(conf.getServerContextPath()); - File warPath = new File(conf.getString(ConfVars.ZEPPELIN_WAR)); - if (warPath.isDirectory()) { + webApp.setContextPath(contextPath); + LOG.info("warPath is: {}", warPath); + File warFile = new File(warPath); + if (warFile.isDirectory()) { // Development mode, read from FS // webApp.setDescriptor(warPath+"/WEB-INF/web.xml"); - webApp.setResourceBase(warPath.getPath()); + webApp.setResourceBase(warFile.getPath()); webApp.setParentLoaderPriority(true); } else { // use packaged WAR - webApp.setWar(warPath.getAbsolutePath()); - File warTempDirectory = new File(conf.getRelativeDir(ConfVars.ZEPPELIN_WAR_TEMPDIR)); + webApp.setWar(warFile.getAbsolutePath()); + File warTempDirectory = new File(conf.getRelativeDir(ConfVars.ZEPPELIN_WAR_TEMPDIR) + contextPath); warTempDirectory.mkdir(); LOG.info("ZeppelinServer Webapp path: {}", warTempDirectory.getPath()); webApp.setTempDirectory(warTempDirectory); @@ -463,7 +445,27 @@ private static WebAppContext setupWebAppContext( webApp.setInitParameter( "org.eclipse.jetty.servlet.Default.dirAllowed", Boolean.toString(conf.getBoolean(ConfVars.ZEPPELIN_SERVER_DEFAULT_DIR_ALLOWED))); - return webApp; } + + private static void initWebApp(WebAppContext webApp) { + webApp.addEventListener( + new ServletContextListener() { + @Override + public void contextInitialized(ServletContextEvent servletContextEvent) { + servletContextEvent + .getServletContext() + .setAttribute(ServletProperties.SERVICE_LOCATOR, sharedServiceLocator); + } + + @Override + public void contextDestroyed(ServletContextEvent servletContextEvent) {} + }); + + // Create `ZeppelinServer` using reflection and setup REST Api + setupRestApiContextHandler(webApp, conf); + + // Notebook server + setupNotebookServer(webApp, conf, sharedServiceLocator); + } } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java index ca8ff95f6f5..d1075471927 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java @@ -191,6 +191,8 @@ private static void start(boolean withAuth, zeppelinHome.getAbsolutePath()); System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_WAR.getVarName(), new File("../zeppelin-web/dist").getAbsolutePath()); + System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_ANGULAR_WAR.getVarName(), + new File("../zeppelin-web-angular/dist").getAbsolutePath()); System.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_CONF_DIR.getVarName(), confDir.getAbsolutePath()); System.setProperty( @@ -208,6 +210,7 @@ private static void start(boolean withAuth, // some test profile does not build zeppelin-web. // to prevent zeppelin starting up fail, create zeppelin-web/dist directory new File("../zeppelin-web/dist").mkdirs(); + new File("../zeppelin-web-angular/dist").mkdirs(); LOG.info("Staring test Zeppelin up..."); ZeppelinConfiguration conf = ZeppelinConfiguration.create(); diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 9d8cafef99e..5459ffd2b35 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -5,7 +5,7 @@ "postinstall": "npm run build:projects", "ng": "./node_modules/.bin/ng", "start": "ng serve --proxy-config proxy.conf.js --extra-webpack-config webpack.partial.js", - "build": "ng build --prod --extra-webpack-config webpack.partial.js", + "build": "ng build --prod --extra-webpack-config webpack.partial.js --base-href /next/", "build:projects": "npm run build-project:sdk && npm run build-project:vis && npm run build-project:helium", "build-helium-vis-example": " ng build --project helium-vis-example", "build-project:sdk": " ng build --project zeppelin-sdk", diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml index e0a1f7b3e84..cae521489e7 100644 --- a/zeppelin-web-angular/pom.xml +++ b/zeppelin-web-angular/pom.xml @@ -26,7 +26,7 @@ zeppelin-web-angular war 0.9.0-SNAPSHOT - Zeppelin: web Application + Zeppelin: web angular Application From be80af7ce3d75977452ef8e366537ee4d07505b8 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Fri, 3 Jan 2020 09:44:06 +0800 Subject: [PATCH 19/32] [ZEPPELIN-4530] Support versions switch ### What is this PR for? Add the versions switch button in the top drop-down menu ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4530 ### How should this be tested? N/A ### Screenshots (if appropriate) ![image](https://user-images.githubusercontent.com/22736418/71655910-192c2080-2d74-11ea-85da-295521d5e919.png) --- ![image](https://user-images.githubusercontent.com/22736418/71655912-1d583e00-2d74-11ea-9663-90a86c32f85a.png) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3584 from hsuanxyz/feat/version-switch and squashes the following commits: 215dc2c5b [Hsuan Lee] chore: hidden the helium link 3af3f53fa [Hsuan Lee] feat: add support switch versions --- .../src/app/share/header/header.component.html | 8 +++++--- zeppelin-web/src/components/navbar/navbar.html | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html index 645da9aa22b..33d8ecd857b 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.html +++ b/zeppelin-web-angular/src/app/share/header/header.component.html @@ -56,9 +56,9 @@ [routerLink]="['/credential']">Credential
    • -
    • - Helium -
    • + + +
    • Configuration
    • @@ -66,6 +66,8 @@
    • Logout
    • +
    • +
    • Old Version
    diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html index 263ff0679a2..818258523a2 100644 --- a/zeppelin-web/src/components/navbar/navbar.html +++ b/zeppelin-web/src/components/navbar/navbar.html @@ -105,6 +105,8 @@
  • Cluster
  • Logout
  • + +
  • Try the new Zeppelin
  • From a62d89345985d66d7f381b45d6870a255fa5b9c4 Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Tue, 7 Jan 2020 14:35:47 +0800 Subject: [PATCH 20/32] [ZEPPELIN-4542] Websocket client support of auto-reconnect ### What is this PR for? Websocket client support of auto-reconnect ### What type of PR is it? [Feature] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4542 ### How should this be tested? N/A ### Screenshots (if appropriate) N/A ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3590 from hsuanxyz/feat/network-reconnect and squashes the following commits: ab8da4584 [Hsuan Lee] feat: support the websocket reconnect --- .../projects/zeppelin-sdk/src/message.ts | 4 ++ .../pages/workspace/workspace.component.html | 3 +- .../pages/workspace/workspace.component.less | 4 -- .../pages/workspace/workspace.component.ts | 41 ++++++++++++++----- .../app/pages/workspace/workspace.module.ts | 7 +++- .../about-zeppelin.component.html | 2 +- 6 files changed, 42 insertions(+), 19 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts index 65ceec605de..4505e365726 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts @@ -116,6 +116,10 @@ export class Message { this.send(OP.PING); } + close() { + this.close$.next(); + } + opened(): Observable { return this.open$.asObservable(); } diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html index c41cf78dbec..a955afa0056 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.html @@ -10,8 +10,7 @@ ~ limitations under the License. --> -
    +
    -Connecting WebSocket ... diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less index 63064aabd16..dfe293f383c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.less @@ -18,9 +18,5 @@ min-height: 100vh; display: block; position: relative; - - &.blur { - filter: blur(4px); - } } }); diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts index 410ef17c7f3..19175cb1be3 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts @@ -10,16 +10,15 @@ * limitations under the License. */ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, OnDestroy, OnInit } from '@angular/core'; import { Subject } from 'rxjs'; -import { filter, map, startWith, takeUntil, tap } from 'rxjs/operators'; +import { takeUntil } from 'rxjs/operators'; -import { ActivatedRoute, NavigationEnd, Route, Router } from '@angular/router'; -import { publishedSymbol, Published } from '@zeppelin/core/paragraph-base/published'; +import { publishedSymbol } from '@zeppelin/core/paragraph-base/published'; import { HeliumManagerService } from '@zeppelin/helium-manager'; import { MessageService } from '@zeppelin/services'; import { setTheme } from '@zeppelin/visualizations/g2.config'; -import { log } from 'ng-zorro-antd/core'; +import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ selector: 'zeppelin-workspace', @@ -29,26 +28,48 @@ import { log } from 'ng-zorro-antd/core'; }) export class WorkspaceComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); - websocketConnected = false; + private messageId = null; publishMode = false; constructor( public messageService: MessageService, private cdr: ChangeDetectorRef, + private nzMessageService: NzMessageService, private heliumManagerService: HeliumManagerService ) {} - onActivate(e) { - this.publishMode = e && e[publishedSymbol]; + onActivate(component) { + this.publishMode = component && component[publishedSymbol]; this.cdr.markForCheck(); } - ngOnInit() { + /** + * Close the old connection manually when the network is offline + * and connect a new, the {@link MessageService} will auto-retry + */ + @HostListener('window:offline') + onOffline() { + this.messageService.close(); + this.messageService.connect(); + } + + setUpWebsocketReconnectMessage() { this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(data => { - this.websocketConnected = data; + if (!data) { + if (this.messageId === null) { + this.messageId = this.nzMessageService.loading('Connecting WebSocket ...', { nzDuration: 0 }).messageId; + } + } else { + this.nzMessageService.remove(this.messageId); + this.messageId = null; + } this.cdr.markForCheck(); }); + } + + ngOnInit() { setTheme(); + this.setUpWebsocketReconnectMessage(); this.heliumManagerService.initPackages(); } diff --git a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts index f6e01e28861..3be5f544986 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.module.ts @@ -19,9 +19,11 @@ import { RouterModule } from '@angular/router'; import { HeliumManagerModule } from '@zeppelin/helium-manager'; import { ShareModule } from '@zeppelin/share'; -import { WorkspaceRoutingModule } from './workspace-routing.module'; +import { NzMessageModule } from 'ng-zorro-antd/message'; import { WorkspaceComponent } from './workspace.component'; +import { WorkspaceRoutingModule } from './workspace-routing.module'; + @NgModule({ declarations: [WorkspaceComponent], imports: [ @@ -31,7 +33,8 @@ import { WorkspaceComponent } from './workspace.component'; HttpClientModule, ShareModule, RouterModule, - HeliumManagerModule + HeliumManagerModule, + NzMessageModule ] }) export class WorkspaceModule {} diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html index c7d8cc5d73c..33a5d87ee68 100644 --- a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html @@ -12,7 +12,7 @@ diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts index e69b89e7c84..b4c20c242cc 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.ts +++ b/zeppelin-web-angular/src/app/share/header/header.component.ts @@ -20,6 +20,7 @@ import { filter, takeUntil } from 'rxjs/operators'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk'; import { MessageService, TicketService } from '@zeppelin/services'; +import { NotebookSearchService } from '@zeppelin/services/notebook-search.service'; import { AboutZeppelinComponent } from '@zeppelin/share/about-zeppelin/about-zeppelin.component'; @Component({ @@ -32,6 +33,7 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, private destroy$ = new Subject(); connectStatus = 'error'; noteListVisible = false; + queryStr: string | null = null; about() { this.nzModalService.create({ @@ -46,6 +48,13 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, this.ticketService.logout().subscribe(); } + onSearch() { + this.queryStr = this.queryStr.trim(); + if (this.queryStr) { + this.router.navigate(['/search', this.queryStr]); + } + } + @MessageListener(OP.CONFIGURATIONS_INFO) getConfiguration(data: MessageReceiveDataTypeMap[OP.CONFIGURATIONS_INFO]) { this.ticketService.setConfiguration(data); @@ -56,6 +65,7 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, private nzModalService: NzModalService, public messageService: MessageService, private router: Router, + private notebookSearchService: NotebookSearchService, private cdr: ChangeDetectorRef ) { super(messageService); @@ -76,6 +86,11 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, this.noteListVisible = false; this.cdr.markForCheck(); }); + + this.notebookSearchService + .queried() + .pipe(takeUntil(this.destroy$)) + .subscribe(queryStr => (this.queryStr = queryStr)); } ngOnDestroy() { diff --git a/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts b/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts new file mode 100644 index 00000000000..c2eb7aa3965 --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts @@ -0,0 +1,43 @@ +/* + * 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 { computeLineStartsMap, getLineAndCharacterFromPosition } from '@zeppelin/utility/line-map'; + +export interface KeywordPosition { + line: number; + character: number; + length: number; +} + +export function getKeywordPositions(keywords: string[], str: string): KeywordPosition[] { + const highlightPositions = []; + const lineMap = computeLineStartsMap(str); + + keywords.forEach((keyword: string) => { + const positions = []; + const keywordReg = new RegExp(keyword, 'ig'); + let posMatch = keywordReg.exec(str); + + while (posMatch !== null) { + const { line, character } = getLineAndCharacterFromPosition(lineMap, posMatch.index); + positions.push({ + line, + character, + length: keyword.length + }); + posMatch = keywordReg.exec(str); + } + highlightPositions.push(...positions); + }); + + return highlightPositions; +} diff --git a/zeppelin-web-angular/src/app/utility/line-map.ts b/zeppelin-web-angular/src/app/utility/line-map.ts new file mode 100644 index 00000000000..30c40793c81 --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/line-map.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ + +const LF_CHAR = 10; +const CR_CHAR = 13; +const LINE_SEP_CHAR = 8232; +const PARAGRAPH_CHAR = 8233; + +export function computeLineStartsMap(text) { + const result = [0]; + let pos = 0; + while (pos < text.length) { + const char = text.charCodeAt(pos++); + // Handles the "CRLF" line break. In that case we peek the character + // after the "CR" and check if it is a line feed. + if (char === CR_CHAR) { + if (text.charCodeAt(pos) === LF_CHAR) { + pos++; + } + result.push(pos); + } else if (char === LF_CHAR || char === LINE_SEP_CHAR || char === PARAGRAPH_CHAR) { + result.push(pos); + } + } + result.push(pos); + return result; +} + +function findClosestLineStartPosition(linesMap, position, low = 0, high = linesMap.length - 1) { + let _low = low; + let _high = high; + while (_low <= _high) { + const pivotIdx = Math.floor((_low + _high) / 2); + const pivotEl = linesMap[pivotIdx]; + if (pivotEl === position) { + return pivotIdx; + } else if (position > pivotEl) { + _low = pivotIdx + 1; + } else { + _high = pivotIdx - 1; + } + } + // In case there was no exact match, return the closest "lower" line index. We also + // subtract the index by one because want the index of the previous line start. + return _low - 1; +} + +export function getLineAndCharacterFromPosition(lineStartsMap, position) { + const lineIndex = findClosestLineStartPosition(lineStartsMap, position); + return { character: position - lineStartsMap[lineIndex], line: lineIndex }; +} diff --git a/zeppelin-web-angular/src/app/visualizations/g2.config.ts b/zeppelin-web-angular/src/app/visualizations/g2.config.ts index aa5a4e9e30e..622d25ddb74 100644 --- a/zeppelin-web-angular/src/app/visualizations/g2.config.ts +++ b/zeppelin-web-angular/src/app/visualizations/g2.config.ts @@ -124,7 +124,6 @@ const zeppelinTheme = { export function setTheme() { const theme = G2.Util.deepMix(G2.Global, zeppelinTheme); - console.log(zeppelinTheme); // tslint:disable-next-line:no-any (G2.Global as any).setTheme(theme); } From 39063312791ce31d65c687be66a4258fbd2a8c8f Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Tue, 7 Jan 2020 09:47:56 +0800 Subject: [PATCH 22/32] [ZEPPELIN-4540] Convert code editor font size units ### What is this PR for? Convert code editor font size units (from pt to px). ### What type of PR is it? [Bug Fix] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4540 ### How should this be tested? N/A ### Screenshots (if appropriate) N/A ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Hsuan Lee Closes #3588 from hsuanxyz/fix/code-editor-font-size and squashes the following commits: 3778a12ce [Hsuan Lee] fix: convert code editor font size units --- .../code-editor/code-editor.component.ts | 3 ++- .../src/app/utility/css-unit-conversion.ts | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 zeppelin-web-angular/src/app/utility/css-unit-conversion.ts diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index bfae433371d..99cc97d14b6 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -31,6 +31,7 @@ import IEditor = monaco.editor.IEditor; import { InterpreterBindingItem } from '@zeppelin/sdk'; import { CompletionService, MessageService } from '@zeppelin/services'; +import { pt2px } from '@zeppelin/utility/css-unit-conversion'; import { NotebookParagraphControlComponent } from '../control/control.component'; @Component({ @@ -139,7 +140,7 @@ export class NotebookParagraphCodeEditorComponent implements OnChanges, OnDestro if (this.editor) { this.editor.updateOptions({ readOnly: this.readOnly, - fontSize: this.fontSize, + fontSize: pt2px(this.fontSize), renderLineHighlight: this.focus ? 'all' : 'none', minimap: { enabled: false }, lineNumbers: this.lineNumbers ? 'on' : 'off', diff --git a/zeppelin-web-angular/src/app/utility/css-unit-conversion.ts b/zeppelin-web-angular/src/app/utility/css-unit-conversion.ts new file mode 100644 index 00000000000..19d4057f45c --- /dev/null +++ b/zeppelin-web-angular/src/app/utility/css-unit-conversion.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export function pt2px(pt: number): number { + return pt / (3 / 4); +} From c45ddc3c0a28fc2cd632d67ef12de9d452d6e7cf Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Tue, 7 Jan 2020 11:38:39 +0800 Subject: [PATCH 23/32] [ZEPPELIN-4543]. Support Shiny in Spark Interpreter ### What is this PR for? We support shiny in R interpreter in ZEPPELIN-4525, this ticket is to extend it in SparkInterpreter where R is also supported. Writing shiny app in SparkInterpreter is almost the same as do it in R interpreter, but also with additional support of Spark. Main thing is in `SparkShinyInterpreter` which extends `ShinyInterpreter` ### What type of PR is it? [ Feature ] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4543 ### How should this be tested? * CI pass ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3593 from zjffdu/ZEPPELIN-4543 and squashes the following commits: 4b1d045c7 [Jeff Zhang] [ZEPPELIN-4543]. Support Shiny in Spark Interpreter --- .../apache/zeppelin/r/ShinyInterpreter.java | 11 +- .../zeppelin/r/ShinyInterpreterTest.java | 2 +- spark/interpreter/pom.xml | 8 ++ .../zeppelin/spark/SparkIRInterpreter.java | 14 +- .../zeppelin/spark/SparkShinyInterpreter.java | 43 ++++++ .../main/resources/interpreter-setting.json | 22 ++- .../spark/SparkShinyInterpreterTest.java | 128 ++++++++++++++++++ .../src/test/resources/spark_server.R | 23 ++++ .../interpreter/src/test/resources/spark_ui.R | 35 +++++ .../zeppelin/jupyter/JupyterKernelClient.java | 6 +- 10 files changed, 284 insertions(+), 8 deletions(-) create mode 100644 spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java create mode 100644 spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java create mode 100644 spark/interpreter/src/test/resources/spark_server.R create mode 100644 spark/interpreter/src/test/resources/spark_ui.R diff --git a/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java b/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java index b2dc5f331a7..3d0f24b582d 100644 --- a/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java +++ b/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java @@ -65,6 +65,7 @@ public void open() throws InterpreterException { this.z = new RZeppelinContext(getInterpreterGroup().getInterpreterHookRegistry(), 1000); } + @Override public void close() throws InterpreterException { for (Map.Entry entry : shinyIRInterpreters.entrySet()) { @@ -133,7 +134,7 @@ private IRInterpreter getIRInterpreter(String shinyApp) throws InterpreterExcept synchronized (shinyIRInterpreters) { irInterpreter = shinyIRInterpreters.get(shinyApp); if (irInterpreter == null) { - irInterpreter = new IRInterpreter(properties); + irInterpreter = createIRInterpreter(); irInterpreter.setInterpreterGroup(getInterpreterGroup()); irInterpreter.open(); shinyIRInterpreters.put(shinyApp, irInterpreter); @@ -142,4 +143,12 @@ private IRInterpreter getIRInterpreter(String shinyApp) throws InterpreterExcept return irInterpreter; } + /** + * Subclass can overwrite this. e.g. SparkShinyInterpreter. + * @return + */ + protected IRInterpreter createIRInterpreter() { + return new IRInterpreter(properties); + } + } diff --git a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java b/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java index def64361020..2819ca51639 100644 --- a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java +++ b/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java @@ -47,7 +47,7 @@ public class ShinyInterpreterTest { - private ShinyInterpreter interpreter; + protected ShinyInterpreter interpreter; @Before public void setUp() throws InterpreterException { diff --git a/spark/interpreter/pom.xml b/spark/interpreter/pom.xml index 86a5f754145..dfebec8965b 100644 --- a/spark/interpreter/pom.xml +++ b/spark/interpreter/pom.xml @@ -329,6 +329,14 @@ 0.4.4 test + + + com.mashape.unirest + unirest-java + 1.4.9 + test + + diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java index 004ce98ea24..ee16c7266ea 100644 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java +++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java @@ -58,8 +58,20 @@ protected boolean isSecretSupported() { return this.sparkVersion.isSecretSocketSupported(); } + /** + * We can inject SparkInterpreter in the case that SparkIRInterpreter is used by + * SparkShinyInterpreter in which case it is not in the same InterpreterGroup of + * SparkInterpreter. + * @param sparkInterpreter + */ + public void setSparkInterpreter(SparkInterpreter sparkInterpreter) { + this.sparkInterpreter = sparkInterpreter; + } + public void open() throws InterpreterException { - this.sparkInterpreter = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class); + if (sparkInterpreter == null) { + this.sparkInterpreter = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class); + } this.sc = sparkInterpreter.getSparkContext(); this.jsc = sparkInterpreter.getJavaSparkContext(); this.sparkVersion = new SparkVersion(sc.version()); diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java new file mode 100644 index 00000000000..c5dc1428d47 --- /dev/null +++ b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.zeppelin.spark; + +import org.apache.zeppelin.interpreter.InterpreterException; +import org.apache.zeppelin.r.IRInterpreter; +import org.apache.zeppelin.r.ShinyInterpreter; + +import java.util.Properties; + +/** + * The same function as ShinyInterpreter, but support Spark as well. + */ +public class SparkShinyInterpreter extends ShinyInterpreter { + public SparkShinyInterpreter(Properties properties) { + super(properties); + } + + protected IRInterpreter createIRInterpreter() { + SparkIRInterpreter interpreter = new SparkIRInterpreter(properties); + try { + interpreter.setSparkInterpreter(getInterpreterInTheSameSessionByClassName(SparkInterpreter.class)); + return interpreter; + } catch (InterpreterException e) { + throw new RuntimeException("Fail to set spark interpreter for SparkIRInterpreter", e); + } + } +} diff --git a/spark/interpreter/src/main/resources/interpreter-setting.json b/spark/interpreter/src/main/resources/interpreter-setting.json index 5fbccaf6cba..100c97c23b2 100644 --- a/spark/interpreter/src/main/resources/interpreter-setting.json +++ b/spark/interpreter/src/main/resources/interpreter-setting.json @@ -238,7 +238,8 @@ "editor": { "language": "python", "editOnDblClick": false, - "completionSupport": true + "completionSupport": true, + "completionKey": "TAB" } }, { @@ -278,7 +279,8 @@ "editor": { "language": "r", "editOnDblClick": false, - "completionSupport": false + "completionSupport": false, + "completionKey": "TAB" } }, { @@ -290,7 +292,21 @@ "editor": { "language": "r", "editOnDblClick": false, - "completionSupport": true + "completionSupport": true, + "completionKey": "TAB" + } + }, + { + "group": "spark", + "name": "shiny", + "className": "org.apache.zeppelin.spark.SparkShinyInterpreter", + "properties": { + }, + "editor": { + "language": "r", + "editOnDblClick": false, + "completionSupport": true, + "completionKey": "TAB" } }, { diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java new file mode 100644 index 00000000000..eb0e56c6d19 --- /dev/null +++ b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.zeppelin.spark; + +import com.mashape.unirest.http.HttpResponse; +import com.mashape.unirest.http.Unirest; +import com.mashape.unirest.http.exceptions.UnirestException; +import org.apache.commons.io.IOUtils; +import org.apache.zeppelin.interpreter.InterpreterContext; +import org.apache.zeppelin.interpreter.InterpreterException; +import org.apache.zeppelin.interpreter.InterpreterGroup; +import org.apache.zeppelin.interpreter.InterpreterResult; +import org.apache.zeppelin.interpreter.InterpreterResultMessage; +import org.apache.zeppelin.interpreter.LazyOpenInterpreter; +import org.apache.zeppelin.r.ShinyInterpreterTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.util.List; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class SparkShinyInterpreterTest extends ShinyInterpreterTest { + + private SparkInterpreter sparkInterpreter; + + @Before + public void setUp() throws InterpreterException { + Properties properties = new Properties(); + properties.setProperty("master", "local[*]"); + properties.setProperty("spark.app.name", "test"); + + InterpreterContext context = getInterpreterContext(); + InterpreterContext.set(context); + interpreter = new SparkShinyInterpreter(properties); + + InterpreterGroup interpreterGroup = new InterpreterGroup(); + interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(interpreter), "session_1"); + interpreter.setInterpreterGroup(interpreterGroup); + + sparkInterpreter = new SparkInterpreter(properties); + interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkInterpreter), "session_1"); + sparkInterpreter.setInterpreterGroup(interpreterGroup); + + interpreter.open(); + } + + @After + public void tearDown() throws InterpreterException { + if (interpreter != null) { + interpreter.close(); + } + } + + @Test + public void testSparkShinyApp() throws IOException, InterpreterException, InterruptedException, UnirestException { + /****************** Launch Shiny app with default app name *****************************/ + InterpreterContext context = getInterpreterContext(); + context.getLocalProperties().put("type", "ui"); + InterpreterResult result = + interpreter.interpret(IOUtils.toString(getClass().getResource("/spark_ui.R")), context); + assertEquals(InterpreterResult.Code.SUCCESS, result.code()); + + context = getInterpreterContext(); + context.getLocalProperties().put("type", "server"); + result = interpreter.interpret(IOUtils.toString(getClass().getResource("/spark_server.R")), context); + assertEquals(InterpreterResult.Code.SUCCESS, result.code()); + + final InterpreterContext context2 = getInterpreterContext(); + context2.getLocalProperties().put("type", "run"); + Thread thread = new Thread(() -> { + try { + interpreter.interpret("", context2); + } catch (Exception e) { + e.printStackTrace(); + } + }); + thread.start(); + // wait for the shiny app start + Thread.sleep(5 * 1000); + // extract shiny url + List resultMessages = context2.out.toInterpreterResultMessage(); + assertEquals(1, resultMessages.size()); + assertEquals(InterpreterResult.Type.HTML, resultMessages.get(0).getType()); + String resultMessageData = resultMessages.get(0).getData(); + assertTrue(resultMessageData, resultMessageData.contains(" response = Unirest.get(shinyURL).asString(); + if (sparkInterpreter.getSparkVersion().isSpark2()) { + assertEquals(200, response.getStatus()); + assertTrue(response.getBody(), response.getBody().contains("Spark Version")); + } else { + // spark 1.x will fail due to sparkR.version is not available for spark 1.x + assertEquals(500, response.getStatus()); + assertTrue(response.getBody(), + response.getBody().contains("could not find function \"sparkR.version\"")); + } + } +} diff --git a/spark/interpreter/src/test/resources/spark_server.R b/spark/interpreter/src/test/resources/spark_server.R new file mode 100644 index 00000000000..071631dd79f --- /dev/null +++ b/spark/interpreter/src/test/resources/spark_server.R @@ -0,0 +1,23 @@ +# Define server logic to summarize and view selected dataset ---- +server <- function(input, output) { + + # Return the requested dataset ---- + datasetInput <- reactive({ + switch(input$dataset, + "rock" = as.DataFrame(rock), + "pressure" = as.DataFrame(pressure), + "cars" = as.DataFrame(cars)) + }) + + # Generate a summary of the dataset ---- + output$summary <- renderPrint({ + dataset <- datasetInput() + showDF(summary(dataset)) + }) + + # Show the first "n" observations ---- + output$view <- renderTable({ + head(datasetInput(), n = input$obs) + }) + +} \ No newline at end of file diff --git a/spark/interpreter/src/test/resources/spark_ui.R b/spark/interpreter/src/test/resources/spark_ui.R new file mode 100644 index 00000000000..a81ad0c2bcd --- /dev/null +++ b/spark/interpreter/src/test/resources/spark_ui.R @@ -0,0 +1,35 @@ +# Define UI for dataset viewer app ---- +ui <- fluidPage( + +# App title ---- +titlePanel(paste("Spark Version", sparkR.version(), sep=":")), + +# Sidebar layout with a input and output definitions ---- +sidebarLayout( + +# Sidebar panel for inputs ---- +sidebarPanel( + +# Input: Selector for choosing dataset ---- +selectInput(inputId = "dataset", +label = "Choose a dataset:", +choices = c("rock", "pressure", "cars")), + +# Input: Numeric entry for number of obs to view ---- +numericInput(inputId = "obs", +label = "Number of observations to view:", +value = 10) +), + +# Main panel for displaying outputs ---- +mainPanel( + +# Output: Verbatim text for data summary ---- +verbatimTextOutput("summary"), + +# Output: HTML table with requested number of observations ---- +tableOutput("view") + +) +) +) \ No newline at end of file diff --git a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java index deb4afa70e3..1f4e2005599 100644 --- a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java +++ b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java @@ -104,8 +104,10 @@ public void setInterpreterContext(InterpreterContext context) { * @throws IOException */ private boolean checkForShinyApp(String response) throws IOException { - if (context.getInterpreterClassName() != null && - context.getInterpreterClassName().equals("org.apache.zeppelin.r.ShinyInterpreter")) { + String intpClassName = context.getInterpreterClassName(); + if (intpClassName != null && + (intpClassName.equals("org.apache.zeppelin.r.ShinyInterpreter") || + intpClassName.equals("org.apache.zeppelin.spark.SparkShinyInterpreter"))) { Matcher matcher = ShinyListeningPattern.matcher(response); if (matcher.matches()) { String url = matcher.group(1); From 62849c71d3fe984e6232e9425311494cec16c253 Mon Sep 17 00:00:00 2001 From: Michael Werner Date: Sun, 12 Jan 2020 11:05:58 +0100 Subject: [PATCH 24/32] [minor] Fix Markdown syntax highlighting of kotlin README ### What is this PR for? Displaying Readme.md with proper syntax highligthing ### What type of PR is it? Documentation Author: Michael Werner Closes #3594 from Xaseron/patch-1 and squashes the following commits: 129d1c93a [Michael Werner] Fix Markdown syntax highlighting --- kotlin/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kotlin/README.md b/kotlin/README.md index 0b71c240c1e..8e3420c4914 100644 --- a/kotlin/README.md +++ b/kotlin/README.md @@ -8,7 +8,7 @@ Here is the guide to its implementation and how it can be improved and tested. For interactive Kotlin execution, an instance of `KotlinRepl` is created. To set REPL properties (such as classpath, generated classes output directory, max result, etc.), pass `KotlinReplProperties` to its constructor. For example: -```$java +```java KotlinReplProperties replProperties = new KotlinReplProperties() .maxResult(1000) .shortenTypes(true); @@ -22,7 +22,7 @@ making the receiver's fields and methods accessible. To add your variables/functions, extend `KotlinReceiver` class (in separate file), declare your fields and methods, and pass an instance of it to `KotlinReplProperties`. Example: -```$java +```java // In separate file: class CustomReceiver extends KotlinReceiver { public int myValue = 1 // will be converted to Kotlin "var myValue: Int" @@ -80,4 +80,4 @@ can not use things like `forEach` because of ambiguity between `Iterable.forE (`foreach` from Spark's API does work, though). * The scoped mode for Kotlin Spark Interpreter currently has issues with having the same class output directory for different intepreters, leading to overwriting classes. Adding prefixes to generated classes or putting them - in separate directories leads to `ClassNotFoundException` on Spark executors. \ No newline at end of file + in separate directories leads to `ClassNotFoundException` on Spark executors. From ee339f6bbfe8a114fb11b71a798d98160d4aa5b0 Mon Sep 17 00:00:00 2001 From: bobcanthelpyou Date: Tue, 14 Jan 2020 08:35:55 +0100 Subject: [PATCH 25/32] [MINOR] Use KERBEROS_REFRESH_INTERVAL in docs ### What is this PR for? In the PR https://github.com/apache/zeppelin/pull/2443/files the ENV `LAUNCH_KERBEROS_REFRESH_INTERVAL` was renamed to `KERBEROS_REFRESH_INTERVAL` The old ENV name is still used in the shell documentation ### What type of PR is it? [Documentation] ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4553 Author: bobcanthelpyou Closes #3595 from bobcanthelpyou/kerberos and squashes the following commits: eef137d0d [bobcanthelpyou] [MINOR] Use KERBEROS_REFRESH_INTERVAL in docs --- docs/interpreter/shell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/interpreter/shell.md b/docs/interpreter/shell.md index 9da2f091ad8..c38391b8e14 100644 --- a/docs/interpreter/shell.md +++ b/docs/interpreter/shell.md @@ -91,7 +91,7 @@ For changing the default behavior of when to renew Kerberos ticket following cha ```bash # Change Kerberos refresh interval (default value is 1d). Allowed postfix are ms, s, m, min, h, and d. -export LAUNCH_KERBEROS_REFRESH_INTERVAL=4h +export KERBEROS_REFRESH_INTERVAL=4h # Change kinit number retries (default value is 5), which means if the kinit command fails for 5 retries consecutively it will close the interpreter. export KINIT_FAIL_THRESHOLD=10 ``` From 8f5059c678d3b9846f55d8a463fd851bf2a60956 Mon Sep 17 00:00:00 2001 From: vthinkxie Date: Thu, 16 Jan 2020 10:53:19 +0800 Subject: [PATCH 26/32] [ZEPPELIN-4557] Fix miss apache license header ### What is this PR for? Fix miss apache license header ### What type of PR is it? [Bug Fix] ### What is the Jira issue? [ZEPPELIN-4557] ### How should this be tested? https://travis-ci.org/vthinkxie/zeppelin/builds/637915032 ### Questions: * Does the licenses files need update? no * Is there breaking changes for older versions? no * Does this needs documentation? no Author: vthinkxie Closes #3599 from vthinkxie/ZEPPELIN-4557 and squashes the following commits: 38112dfaa [vthinkxie] [ZEPPELIN-4557] Fix miss apache license header --- .../published/paragraph/paragraph.component.html | 11 +++++++++++ .../published/paragraph/paragraph.component.less | 11 +++++++++++ .../published/paragraph/paragraph.component.ts | 11 +++++++++++ .../share/ng1-migration/ng1-migration.component.html | 11 +++++++++++ .../share/ng1-migration/ng1-migration.component.less | 11 +++++++++++ .../share/ng1-migration/ng1-migration.component.ts | 11 +++++++++++ 6 files changed, 66 insertions(+) diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html index d69a0f43424..4423ddafd7d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html @@ -1,3 +1,14 @@ +
    Date: Thu, 16 Jan 2020 10:02:26 +0800 Subject: [PATCH 27/32] [ZEPPELIN-4554]. Default interpreter for shell interpreter is missing in interpreter-setting.json ### What is this PR for? Default interpreter is missing in shell interpreter's `interpreter-setting.json`, this cause the frontend unable to get right editor setting when using `%sh`. ### What type of PR is it? [Bug Fix ] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4554 ### How should this be tested? * Test is manually ### Screenshots (if appropriate) Before ![image](https://user-images.githubusercontent.com/164491/72487119-e5f39200-3847-11ea-9686-d65bf4e32578.png) After ![image](https://user-images.githubusercontent.com/164491/72487208-3965e000-3848-11ea-8871-9cede8f3fbc9.png) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3596 from zjffdu/ZEPPELIN-4554 and squashes the following commits: 8a9c8b695 [Jeff Zhang] [ZEPPELIN-4554]. Default interpreter for shell interpreter is missing in interpreter-setting.json --- shell/src/main/resources/interpreter-setting.json | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/src/main/resources/interpreter-setting.json b/shell/src/main/resources/interpreter-setting.json index 4a7dae5706d..1db6528457b 100644 --- a/shell/src/main/resources/interpreter-setting.json +++ b/shell/src/main/resources/interpreter-setting.json @@ -3,6 +3,7 @@ "group": "sh", "name": "sh", "className": "org.apache.zeppelin.shell.ShellInterpreter", + "defaultInterpreter": true, "properties": { "shell.command.timeout.millisecs": { "envName": "SHELL_COMMAND_TIMEOUT", From 52d2b4b0b2430573e4d088ea4099c2b4b9bc8a5c Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Thu, 16 Jan 2020 10:41:20 +0800 Subject: [PATCH 28/32] [ZEPPELIN-4551]. upgrade-note.sh Plugin GitNotebookRepo doesn't exist ### What is this PR for? In this PR, we always load NotebookRepo from current classpath first, then fallback to plugin ClassPathLoader. Actually we do it already for new NotebookRepo but miss that for the old NotebookRepo. ### What type of PR is it? [Bug Fix ] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4551 ### How should this be tested? * CI pass ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3598 from zjffdu/ZEPPELIN-4551 and squashes the following commits: 7eb734ce7 [Jeff Zhang] [ZEPPELIN-4551]. upgrade-note.sh Plugin GitNotebookRepo doesn't exist --- .../apache/zeppelin/plugin/PluginManager.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java index cdcfed09861..032773e452e 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/plugin/PluginManager.java @@ -100,17 +100,14 @@ private String getOldNotebookRepoClassName(String notebookRepoClassName) { */ public OldNotebookRepo loadOldNotebookRepo(String notebookRepoClassName) throws IOException { LOGGER.info("Loading OldNotebookRepo Plugin: " + notebookRepoClassName); - // load plugin from classpath directly when it is test. - // otherwise load it from plugin folder - String isTest = System.getenv("IS_ZEPPELIN_TEST"); - if (isTest != null && isTest.equals("true")) { - try { - OldNotebookRepo notebookRepo = (OldNotebookRepo) - (Class.forName(notebookRepoClassName).newInstance()); - return notebookRepo; - } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - LOGGER.warn("Fail to instantiate notebookrepo from classpath directly:" + notebookRepoClassName); - } + // load plugin from classpath directly first for these builtin NotebookRepo (such as VFSNoteBookRepo + // and GitNotebookRepo). If fails, then try to load it from plugin folder + try { + OldNotebookRepo notebookRepo = (OldNotebookRepo) + (Class.forName(notebookRepoClassName).newInstance()); + return notebookRepo; + } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { + LOGGER.warn("Fail to instantiate notebookrepo from classpath directly:" + notebookRepoClassName); } String simpleClassName = notebookRepoClassName.substring(notebookRepoClassName.lastIndexOf(".") + 1); From 490396cc237f60b83b0f78416461181c2aa9ce70 Mon Sep 17 00:00:00 2001 From: Jeff Zhang Date: Tue, 7 Jan 2020 23:11:22 +0800 Subject: [PATCH 29/32] [ZEPPELIN-4498]. Add document for jupyter interpreter ### What is this PR for? This PR add document for how to use jupyter interpreter in Zeppelin, we mainly talk about 3 kernels: * ipython * ir * julia ### What type of PR is it? [Documentation] ### Todos * [ ] - Task ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4498 ### How should this be tested? * No test needed ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: Jeff Zhang Closes #3600 from zjffdu/ZEPPELIN-4498 and squashes the following commits: 21224bea8 [Jeff Zhang] [ZEPPELIN-4498]. Add document for jupyter interpreter --- .../themes/zeppelin/_navigation.html | 1 + .../zeppelin/img/docs-img/ipython_kernel.png | Bin 0 -> 134015 bytes .../zeppelin/img/docs-img/ir_kernel.png | Bin 0 -> 206755 bytes .../zeppelin/img/docs-img/julia_kernel.png | Bin 0 -> 284921 bytes docs/interpreter/jupyter.md | 134 ++++++++++++++++++ 5 files changed, 135 insertions(+) create mode 100644 docs/assets/themes/zeppelin/img/docs-img/ipython_kernel.png create mode 100644 docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png create mode 100644 docs/assets/themes/zeppelin/img/docs-img/julia_kernel.png create mode 100644 docs/interpreter/jupyter.md diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html index 68252efa8f1..a1796e70517 100644 --- a/docs/_includes/themes/zeppelin/_navigation.html +++ b/docs/_includes/themes/zeppelin/_navigation.html @@ -142,6 +142,7 @@
  • Hive
  • Ignite
  • Java
  • +
  • Jupyter
  • Kotlin
  • Kylin
  • Lens
  • diff --git a/docs/assets/themes/zeppelin/img/docs-img/ipython_kernel.png b/docs/assets/themes/zeppelin/img/docs-img/ipython_kernel.png new file mode 100644 index 0000000000000000000000000000000000000000..eefe97e36124535b9c43f8fee47d13f7a1d6f140 GIT binary patch literal 134015 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�dZ1D$Ih9O26zwcL5Fj8(Km#!fTSKq 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 literal 0 HcmV?d00001 diff --git a/docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png b/docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png new file mode 100644 index 0000000000000000000000000000000000000000..a1bf5ec188cfa9da0b8794c03b3ec75643df6f0c GIT binary patch literal 206755 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� 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 BL6!gj literal 0 HcmV?d00001 diff --git a/docs/assets/themes/zeppelin/img/docs-img/julia_kernel.png b/docs/assets/themes/zeppelin/img/docs-img/julia_kernel.png new file mode 100644 index 0000000000000000000000000000000000000000..5c075dc28f099e01999230f63836630bfe389284 GIT binary patch literal 284921 zcmeFZby!u~*9MA63IdW!gP_C)6sb*jO4p{5-gK9QG)PHzcXyX`gVaXpM!G@zF3vB$ zbNtTv>;8A|$MeWu?6u}xGsk$}G2UsAoQ&AhCxlPn;NYH0hzl#g!6Aa+;1F_AkbrNf z>elz+;LxR@LPBy9LPF$nwpK<^b3-^d@t_!0WQbxveyWCogozi5IBE+jB?`h9Y{6i1 za^>=8k^F)|6cmBqwPKa6_bB1FKbL-{X>5eARGF+{^q#Nb2IUtQ2O|>ESt;;O-!6Py zc=?5pVOptdEcNFbm`; z5&6T>ZNBgi5eO0^9_8QMyr4th`=q!*!2QE>b%=Ol?W8K8A{W2rODEM6HBwL5{g1GF zhD(=$jOQ5E-@1|mgDr$T^t-yrOb6qB(PmNS5H+nFB z^u?eS-t3W|6G*%iV!ioZ4RR6ohH0mkJuf8C0L32a)zml2CFAC-|DawfI$`&!7ol3G z!aNGZjneZsefGJdgSAGVgc4d=t6eOm@;ov9%$;H|czR}4NnSf!(&}+VLne*c`~MXbHTV1PYD+t>9D@r5wT;SwKx<5mBGQD1HHtZTri>69JY!pSBoN zrY-Ag+(Rr=s{263PYoOG8Hv|JZfKaQ`%$iSQD{sX?qJvR)Ea;DH0X}1%e)azWBvLoTp(bTps5d`5PG+fxC+K%f{y_>Hb^5K^Gi>{I-+bIX@45+j9Z!d zh0%=47o^j3u6%R{X{SwCr&p7)&=ri_rVr@HE> zdm9=rlq{_&ImbUI#4Wl@#Y=u3B~GOnNl*I)S8OHfiG*SHS+-VoR<=~O<+w&A#*fdt z5@Fxr_iOea2nh1Z#8GV7}qq>oWV_utPQD6aSU;c zI**jesFd~%Suo{kW5zomM?`P`rA$y2GP zb7|pT58{`N7>#g-jS?+bxC~)j<0b}Q#oPOiBd$g7EW;9;;$O#)vMuU)v^Otyj8l#a z8dWT;_==QKPcU~e_u7W8KN}>a_gDTB(`6buC11n`=>cKThbwn;_HS3Q)rD26s9V)q z){&OmR7=#V8C3OdgfUFTS|k}Z_0$g6j*bjide0L#AvG=T(Vm-sthnX8o;bH6CMHoJ zX|*$PbY3x8>9Ygbm|HjR2|GP;q_ZxxYg~D6Z^X69X=S}{Euht`)y2rlNT4OJN~RjL zgET!N?_Eckn*mGV5Yd_s%6`x+1fJsCVJe$XWLAZlr1WIxD;^ zd@gS+uXlQcy|WH>!8sd9GO9hmyDD~wc9wMD)OV257VepG&wJknKL>C7*b#~Q#U_Ug zi{(x|vKO1z&DUWsErH_nkaRNdM(+}z%XWwM3n6nMUy4~lQoCd@I9V&%ID<6f_}k+Q ztNOdShB^HY5QqW91@f`}gR`x(!>@Uiq`=)k|G-x9gT5aTy_qQTWAgM_r6(X~cx|3C ztLB4W4Xd)E6PY+!MOg>E^<91X>aWvrdSoFy%Z|nF#Voa8jIN^GYpm6LSsv!xEls@s~)cSWv4hkmY$JrYFGW`Q=URFG_pF@UcpuJs`m7*e>rMeWC&zrCrXWl)I4?EDh>gK&W_inX;&S4`7>ilq zouiT4Qt#2uuiJ#?p_w7xN2=vAhf2>WHDB&NL;S1~L~4v^R5IWiNfO_}*(62`D#g8! ztdBJ9KS|C{mIhnduG-dZVr=AW?DfCiG+rZ%CX}?xd2I|Cp-CO1wTp@AZ+vot2E#w? z&sv|w4b&^l%=w05`JIU-C3=zW01pvw3b!RCf!WTpLZG7hR|hCgP0EOeF^J~UhK*O_ zO_N2~S+bwq{_y(HJU3=S9JtJ)b?;{UavqJ6U>72;72kANCqf#m!r*!)z0F>dgP(&Y zN#;g$X(5zgnb5p@<@9LLLOp~j7G$ZjQe$u%DZAcrY==jR7lTI@`y@8?+GFTKc@dLw zP#xAfXMEX%*M&EZH?4wHHdisAtK46RT=crwQoU1Mv2|l=X3K0;C9GtwI;>Hqp|prD zx6rU<{t9o0Pbs*l4CV{lEnqFvQn)tqvF^+Xr63|=S2HjCetL)8kIBv^W@%YymtQm| zIHyp(J_d^}$@4V0hqMiwYjoF!&*scFIa2L%s2ynNv`x5e9wSu?{Pw=DKWf{Yd5_9f&o-cvV8#YdOHGK%rA$Yb&DZm;yG}n{4t>pjV##~o^7Fz=1I-f0GH!9K zP0?lg#&W(b`MxG^FmLCurTino{_BOdGycP+EurpC%=w(~pW$?58a$<*E0=3>vcj^x zWKs7&J?K7ie$zP5Yfq~gO-{YNQSH+qxO#Qwz!%3y=2mfW6=iBowF);ou&nL6so(5b5`v`c@W<9}KMY z3>lp*tbwQD;JBSRflCWR`w!&K7Uq_AoX$Lye>}knTt9rxL`nX~Blc!Iln`k-av>{Q zLvmI|7REP}yidr<$+>L}j5rm9MgLtK_=|_q#NOVTlZna6$%)bF9ix@4G1FTx7|isB znTeU10eFJJ&c)LHgENDr-OGPf@}GKy4ej)8q1N_LD@*c+dOzq{IoR`1Qa-%szd!$K zr=c_Sf8Jzi_wQ~29b|gA!}ON%4by+?28wb&e9I{Zbv87I2tzFlE$x7J@Vue_r{gqH2FC`WF1=&qe=q>)%DWnI5|Er!M_#y#DwW7%<)^+)V!+eBLLWDBy?r zAchLdDgmGH4}Sn3ioh?Le|-Yij|OjgJDz`ngX4#j5Ef8!ezco{T#qXP^AFaA$FoCl z_z)Tl))nNJ7oHAzR#p5N`ZQ4OO-8(`$lJ0PIC|P4G)U<2kK^Ca>wP7*xx3n4oS2=c zGtM>MM|WauKI67)YHD1Wo#Lr$11sl=j3A4Bfp>J;3xm2+t2@7x&PdRL)i9*^ERB8i2EdHerO zbvx!c9O)BJ=i-yYj{-N$uZ z*itO@uHoFrfn3+SRr5!^WCt)Ur+K8!puX3KTX|`X5ii9W33S}X91a%d_iAS?DcUrK!KW+Btzc-ThJZYBjrJ^)Q_8&RWPHz2D3%PbNikvDN)# zB@+3d?Y@<3?TgUd2-g8IZ~w{g(XU=IPy4dgtHSFgAIv$*V9-iehWquoi&g@MO(xfV z{pws{QRz0@g0p@dOxh? zO}mwr?T7@$`Kh#uxg0HNrEPat2`7AKlZyL;Ol|hTOs(}h-!g>qn?!=~MNaN7H`Dfk z@2tt(Pa}ZQ7@dPh1IZ~{2pN9%>)_leo>(GjHd!rnt}I0uY}#)eBym}bc=T%{$!edm zVGWyol>5YYU$QF#h1S}t`N%)Xth9kp_vd0;8xgNt{j71C`y8IC=Gc;(qL>L5@5P** zbyxDxC0|)zu4qtKw zkNew;WymN74{~IOk&k!a?>5P+k=lAcg{kp^_a5ecv?rSpDt4hZQ39)Ae*0GHwIS%8 z$BlE{52K_8KYVo>g9wg%r+M&3{L3QgC;HNQJ?$Ai zyz~0a_I_%*4ettK?(MjSkDWB1~ zndaHbwOiiV0r$l@3P0OG$9_y?Kivo8NujfPVs6OwsOR144&-O4`q^%&JmS0Z}IwkoaKFUyAYSWBQ6j#;9iPx$om z;ZY;6_v&<%;z|$dZC1T?i^y1F)r=AjgXMDCLPQX&9{=v1qy?9TB39>jtEz30&1)l@ zjw*uo2LiO6=DF&e?&oar*cX$lrn99b#*X*u79A7!nznM2Hl|*?i@k$0{Gw6-DS)Sj z>{kvl%5-EeWEkeq$}5oV(R<8PLj_o-iiOnlB!{Avb2>2jZk8;Yk9zvx7=&Yw#1egs zz7IgkrQ#Sfp4QFT1_L9%=N<7)ntdLZ>mv@P zd0f%TimP5zou}E4OIQXo)LK{e$sh%dyE+d zcr#x5Q6E7HHDg-KDMiDgW-1vyy*fHI#H$)%^;MENcH#+O9sQ|iCXu$pm|5I*O6t7( z)J?ZtEBV$*r$cpVk4%=ndRZQ?^|ucwC_0RSH;G?MRh85&%s{p8xel6f64qm9$9l5k z4i!St-nJkN3hu?ARv@KzQO)Bf@+RXGzJ%Zxa+Rdou2jY*QImKZg4d+-Vw7`=DQc2^ zK$(VjrO5H6A~ik;ecCOqh-eBt^%LH$?+rc_SOX@4{TDTe0n_F;Fck6$G<15WNh417 z?YcUIwVHTZ=k7R8_f5v>OVJP%%D7xysX=k1mheGS>A|`F`%m5>Zw-nmN|#>WdmL8{oh zRIn*MiPCIcsI;4Dhw(nh%KeAqx!T;AJIp#IE`Cu)*}^O{$LMw|F$Xoa(I5Mg4v&5c zf&-#{K9I@W5SDXOPt*5x)O+0h=BU@}wgZhxv%)W@OXBkCTYZ#D_FI}@nIwP9GYQ-n zw!9Z1u8SUbmz!A?W>C|L5~6kmMedsOw2fY-hPBB3ua7a&B@Yk@G?&h2%$S_^YNkbH zKA?B4$LZ|vH=oFGh13R+x|%Gw`XQ6KS(n%D#*5|0?Cz# z*z_PwE&7DCBrTs=$9WmC4rq1&D{~Zk^)D!cM2U1^lDwgb1;V_^5$$MYdX!)CRc3(i zIFz$|@zTTkGLR%BG&Cw3622JX>qw1FnNDd`pbzuK^d&32N}vS7-aQ z=Hs%6no&bcoA0j|?=j2_dwLx!Eu>pgjVpPGh5mvCh66sK#=7>7ar*VApPim*Ge`>@ zltR68j>S=!AB_+6Q9@?8T3d`ISQL{NQm75+it83!BSg|rKgXcNZl|>jsu5YxKU2_4 zjv-g*msSj5eH$S~3p+pF zhK;)_E+!uxW$NLk)vl5p``&0zewInI9iXLPspT{qgK-+l)k#-C1a@y)7&d)fq zFH~BdjwoYCI1sy1@J#M_QuG(~@U00o_t-K!zgApMj>mn{xG-S0I`{DjQ#8w_->?Zc zbnX{Z^q1+xwe4Md@(C=-%de+GXEX~^d)WLfUZHI_ zl_Ak9>NlfyC$$84rI9V3s>zQ53neilL_Wg1&1VLIip}iVeJ+o~eJBKn^ zGflz?lIn66fLl-nk0i6IU1ifq1t!?cu*bV3yYbK#6hJ8GuTtZe#|Ybx+h2uU0*bTDO4Egel5W-;F|;VwgLuAIZ?C{pfB zti{C@Jlax?aXqiL@&Y)lSYLEQd!N(ZJ`*F3IDy53%Z>x8ZQ93^3IjNDPTD@L#YAui zqQy2oQz|_!XmjQ0@d?VpPLx)H`N(cjYpNw5$Lki@Vbk3*JDTk21VO53vFtI?m8N+4WX<8uSAP}& z+si(mj#c%}bDm1lEpRNCHc_Wdgb$9hd3A$o8W`V4eC)GOCB z@3ct5#2KZ#W!&M{3;>#uK{I4J4J5(y))WypB~McdNTD=#i&87E&D-G_jV;H%lF6lzIdMj1E*^LD9gxEFqw6vIl`no(Yse^K=-Z@CM!UXf*fC?0dfk(kX_Si}{ zEYq3%Pf$gSTw)Q_hB_3y6NM$vUfD{RS6c&MJAh4+xGEjle=0ADjr3GbKCOB6i?jVg zD=DXBRCRuoT>h_Y)?CzB4@sL--7kb?&Iigobh87>ZIXyMpeb#f5QCC<;*jmM8LEmm zm%*RZ>0^qIP}`53b$LS{dO!c`t=u>#_VD ziz(vGi(Pg6%5s)=$U6R2SD8!Yjo@l|0iu*zPaz+6;HtjHo-7XNb|$*PIMwCV+3N6A z)O=W25%fdB)!CcLv(Wo=8^HaFo#D+K4Kn-QnWE$TMv)Du<({@5Ct0-yfiPD^A!;BH z>&_$se_OG-%sZlBzg&FK6kAJO!EnxudNEnQ-8xF_!1Y8~8?u+(yjR^?s^|6n)5J(a z*lYzb2v5iRGUcZy(3@Ahb3!Hzy6HMWTNun61xn@7%EhPbZA1LonE7r{8*Ety6CE4L zJaPtsYtw*%e8c=CR#3|qY(ypnKUTQrpZKuH-)4LP(r5;m7}Ge#JH07lg|Bf;3wQx* zsfMp%OD8a+8c|pJZc4%zvzh0MJlgrW`s`xO&+P8Ev_YT>5q#4k*h+LSEuw~}+|Dag27kd1 zRl{s(JJzpS;?1-WO9-|R^UIBLkIR~m2V`V)CSkv3g74z|zd7=W@DzK#C@YGdNCEhg zU(JgZm&ohJeZOS<7dvYlrz?dgf=MUrj*ye~fyt{Vb+Pea|B<8^4g2p#YMtZE&NfWZ zI}D)tw!1T?;IP^|v@VyT4^99d;;f-2U1RCx!|imX(JRos5adqTGh+x}b1ifnIqvQ) zNHN=0S%rqO!ce+RN}e(;5rD>tPn~VR#WCt{C|>`zD!NciQg}<2*@3;^1du6e$BlcZ z_4i^2Y2C2$=rZ({oqkMT;`LuIzO+k(F3eYP%tv^npFLs7M+fs%u;Q%l9cQXoH)hqa zt{!y9s%lInZP@2QNH4{{H5JB`T`;w9WgJK?ktNjrB_G$DpI~it`{QRT3?Eb2pQB+IoGlcU z1J2vOf@)7B%%wR30?|?CrK3~pRPZ2ML)A1)@WkP3Vl9sPQD?PCBXe+e%#^v)I;kM# zS4$&fG0ElB=5Z^i$#6HBqYKSULBI{-SfCt}5RQCI3|>7_`S=upxt*2@7Y`fMf|wD- z5&H`Asv95G@pz#6V&NkfpD|w}{=xurSHi?|Fn`12lW7k)hlSgLhNm6K-JA}F5?_(|uq(qoG z2!qZulILilLSWO#)r@T20<*l@Y4vjMrB9E&J6~E^%zo8KX&&nT5ILjgor55E>-+`3 zx~~+hC7D{5qg&8eOy*infE^kmvr_J>mLqZJoPL7vTTB{?@V@*#R~|>p=D-UH+IEEz z^Hat>29OWI2Eb!kPy&E%PrW>n41=6nf_!MvY!4|PNsMUYzL%>$@vDV;8)j60j{;h+q*H(3=07q-uyPia{(?ic zjcC;g973W(Fg14xLyvrNFd|r2AuVzc5qGc?{M*D$#bYzxV?PrsgsjWPFvHBBO;rBwM;XSDU1*li_S&RNDBhcs&2&(yeJqwCvnXoDx;ji{xM zzU6R=^Xf!HS?j2itrCmffP@XKG4x0_(VxOya0fgiwiQ!1hn0rCFS57<=}n%?2QlFX zgvS)EpRr&(1fG(Ud6hY-HP@jMLSWbNNY~o)e0x$bECM4h+^xFrS*iCpP08{1tAb_W z(7VYg!q`N#vKs7~o(u#Luec?0%&8{}9n8dLT20k*;xyxpp>&%7aewlo`VG{Lr@5XZ z{#9+?b=2|4!77slk7f_M$}E;Ela{{f^!Dr%KLqLZBgIi6Lez*EStKGF{50iqCD$Dd z3J(<{&2pt=7+Uq+PEQ~*j+sLhl@ClaFgU9Q3v^blGFy$2%dOk%)B3#n+?Y8U8?=rf z5$68cz1jnsA!kCI>No?FQUtH9Gpw)-JFplD@Rf5!lKTO-z) z$T(+wTS_@3N?-l5OY{QD{0sVG3=_eYN}0x_LU*2MJ8u5MZyX!*ufZyEne;^OoPnv2 z1-`T`Xr`gP3f?&j6Du;#s}>Wj3s7Z$moiJ!c7+2S=6!{v6+-^X`E}AbY*5B1bw-APB&C9m*6$>8`7&nXZH9OVH_dc*a86VoZJ^ue3aeE`x9M4e-pt>e#pPN-&D zk9k8UCPnxf8wt|FSuTxM z@w@{y1cQW=1qEGQ3Fh4_Eam(S9Hfsev=SQ`E2Dw)8G(zGN?fx3%X7N$X>3x5xi-)H za%mipVYkBwcyrCAwl+YZ*?e#CQ4p%r48CdFinMUVV~T>QV{Aq*HpW5-pHeJ0@ipxb zSgpH%IeffF2%zyUKUBco$+=XBQd8_E-_pNI?%rJa$>Z27CVpqNUizAxhC$|Qcv478 z@D;$9lFm`=_B8_DX~KKYUWy{1DIc9o%w*NhgaH;6?67x6+bcLRKwDk26Gt3i^nu>L zm)Pz-75O0L_)HpT0zvAmdq(}|2Lt@rO5)n;1vf6bagd&JT+b&L=S6^)QkHG|^*Aeu z4}{H_oI%YlRJr#7TRu8ifSeLaWM!G^B!hf~tqQIbg>^zGo4TZJVpdbD(=T48ursYlGeAspi)UW?WSaU5 zdap-Yc@B^`%`3JS9yf|D4)qUI&IlYdxaP%8=~J{TOe?Hpj;j!MNp~1Op)@b*C%=fh;8}V(TQcIAtj@VW3z+e9pcBgUXBS1&c?sh2T5$h%C4V} z59*adzA@2b%apiTIP6a6_6@$m>@_v!PMKjd|6bl~4?sz5+7i!1e@z;Q&PqqcIH}uV zdj?P8I}f4lX);vZquS3&T@czkd~?Z4r7JxF(t2f;@xjJsBU)atsJ&tV->YafE(3}9 zSHfY$VCJ$C$ueG5dR)Q)y2bB>GBv8+)z7y$hC386sdmCGCJ=aIN|+d=^feBiOXOvy zf9xEA?o2zOw`CK5+^wL{9wdw=I<*dtOQejDwbHx zbIgzFrQHc4_r8&^n$&jd!)=~QS(c9RVYkb<=m?MU$*Om%C|=Lbi4uFm*EjzVup!>-oBe)@e%DUIodu;>rjCVB zg1otTcIp}>LxnTpE?2?l!Z-Af2 zbu{FPNyO!79(ardYL5uQh{P~!u78o7_LE2aAY>eUEq{ur$=68&EEa)m2W|sWAZqWx z-AC^pDYp1NWM5=PyvDs*P{6uJnQG3{VR=*6bqf|X%3nq*+mVQ}@f2;6o89ZoxRSW6 zt77H`4?MU07w(#`&n}>rOSMH!jDsKrn}%-Y0h=$xEKXbF-TnPv(moKzn}ND~N)w1D zKrN@^?axBf+_%?4)Cgt4?XtH{$0IGjR)Pbr^jmA_9Mwe zR@JtnMUD{h`5jg7H}3d5S+$WGA8Im|{9L@htJ{H)>quT3*w+8?CeMZQ9k{brWI&uC2p~2kNOJAB!Lq`I~1jZ6#dNA~p3l5a$SY7LCf2kF;f0cxWA_zT6rVsOJV!k11)TniBHw98%RoI}->^6H>_dJeoE1Ls^s41W7%(52ZK|&}Nx~ zDZqb~KzKF2B=-{cPCyT%G8krGbQ91lZ1RVt3&^%!7I5u;?w!A)2W=pkS2b#wx7M=e zuX~Dw5wg+^HO8zPPz&H!Cpt8q!8BAOdDh0xV#O`sbBiH(RFVT%3h;)p312A`{X7kn z=_)k+-6~nMfHWUHsKDk&VvR0TkiV-lSpk(1U{M{bzqQMQVWM0qm=w~UzhifI z{S6VNJ0h?ky49+wPnCLeGO5ABE8U_I*G|z3RXHQnj$}p~OG=ICA?nCfDnC~eUX*rE zyV6f-?1OPzA3Gid!T&7{tY4j5x$fofgjc`FUCNU{Oj`l6FJ`Y0`xRI znus(1s5w9YL@VgOGpGMXNB>U}^M7ifKP{*Kx%~gH5bEoDYRDas-YwN>^RQg@BXAT7 zz_2)1y-#skuwh?t&f1x&DcS+tLDc~!$?w97f77LhDrDl{v@^8b94{Bjrf^Qxm`#`N zivkHo?j_f=?U?COKv~iEhr;FSr$?5940RzRYBNCitpSiNh#l?z2I>Cun)C+j_yQo7 zlRY8B#Q=c}j8~HS1bxA#ZE`x;=e^#2cQG!-)Bp%4cv+m*`XVfoENW4&WAWQ7Nz14# zy#L|>|1;6~zF*(JhN!?pT{qr7vjr3!HtciOLitzII-U;L)U2Uef*Wi7Q9{i*BIU`c zs)3FFDfgci{VR`WDxvHD3}n}kY&MoDA`O|U+%@o#_6+!LsOr7K+Vj8Sq<=RK=wLp5yX{=P&HkjKti#8>nz#pL!f`wXF~_%-qaGp|#Y{jy z1G9e6$)KqO)Xh64eFSpqbDDO;>ksKxK+7=L@S)Sc0Z^|nWGg1n&2~geF}@g?wQ>76 zF7X=R{2v)1?5#k$-}2YtvgKsHe8v!v3w@OsMlzaJN#=Ga!0vkb^NoXsjQeDd5C*u* zqO$+hQ8x93wD0>Tu>&-{occW>sA-n-jd-}AG}mofc7r~w=}JQ>CzzVC-x*Vh9(Y@x z3z!0r*UNT5q}vJbpLMg=olobN1IR4n9-Qz>&EGid%1BUCvENNY^h0TG z0gVn$@-mHH%NY!9W%1Y1>O3GCTP|(fE+lUi4SKhWiw&BpbJZl2(SshR4iQ6R6+m}ngrrCgyZ?)3o8?mekG-Tb^K2^4;pt$e$h zvcfl^8W!VsfV>WSo7qfK4dVFoTYLXWLvA;{_9YOJOWhxOH;S&9RRTc&WN&bDpHEQb8;ok z7~Z1+;yzOdnO&Ouxs9r(jo&q}gfm&+0h%d8ARRP?1zJUv^qtcW=jmvSo~hFXU?z*S zrhvs5XKKH$;&$8Bc2S>8_&7P_m4prYU*kysZqc`Bgl)<4Xgealr(6zC2Ww#J^c!O?=6P9IlcZ46^jT51ASQeoZHFpJWzaXBf*$-8VGSKVg3Y2akcwyMQ=xA zg6$i7Ko7QFvk8p1jor{&F)YY>J`Jh1+mXoYL1_?ZRq1=cf7k7whtz})9tblH*wrL2 zP>Iw539BD_)e|ya@(SfF)*dOnZ!E5UW`$$OIIZnncj3rZPmI;7d#?*&@~i=h$knB0 z(S~Xcw9gb%2k;2>KWwG!*ArRRQ$#ENl+`RJ=5{U* zu4)7%iIhy6159S}K{4z=Q?NX#RR#vHsN*!TKlgT2Vi~Udz5X@#wO1pMwAef_aqsTL z;2MGw)?PT02!EC3y`(CxGx1&zeD?AWacS-stLib)_T{h(-#x0ymg52Xh&OS*KzQGb zx6lm{oOhI3mt|0S7@cDb?45ycSz?&4y_D9W^Fx55m2vlCZ+7}A883IWAz)m>2SzIO zDGjKBm}T9~Oxx}Gtj~JRxh!}+x^KlE5Nti&qS7S=CVd|mXG}9sZ9vW_Dfw5|_Fsp` zKk+O-=A$hW>Bcy3&UO75=*A81(PSYg)S|`dsM+3QuTL(O;N*Cv#ThVA6Dc$v(LGN4pIF7j z6XR2qmVn2RA?;o#&I9aO#^<}+Yh*O3lBcxvL#|H}TN%SwQn;KjhMA?N1kF5PinCC( zzY@Oxz@QM>bVkI%jZaz=Bh-a}A~>wnVFxB3HM~=s8)Qbu-3I(f1`U4^~^s2VL_fC%V8joUw1EVLBc*1wnlVC92ky)Ufo{`SDK^C>&}NU(aX zx!Rd4E!N*+960!OpzWYIh@|VmQZIDI0T56rj=*%Hi|KYg6uRC*|Y*Ul{1j`6qC37Ele zlL(0=x|i1nZB2j(ecl1^MSx09TY9)+<;tpQkL{v|$g184gR}2}=8Fu1cZ#btfoQ`V z;5oG4%;%+fY>S2wZ#@{->6VX9bpW;#ftHkxq;NF>um`5)_``7jWRwpxbr{&3^E6tp z6frXQ$p;V0bP3?wReT+{qvm>7PAnm?cx1pSo(iNr#bqNQ!{zqs%nneALcXW{o%Vc6 zk-+3{S7>|&Dge7K0gTlMK%jS+_04Mc>r9?D4>1EVQkU!pILl!Loz}48xd4p#+B#GQ z84zVw5xv#({R4Iacw4J_>jC2>0Vr|~fXYPK*Fbf14^n)83=+bWrqgk$`PS=wA`&v^ zC9nOJU?z-}pMC_|KiOtXUOt%ddO$wiAz@NoKEk;J2!?xpd^n_OUGhe2e8^!2c9{lr zNW4y2L&78_KHm#Jb^s!F7(_M7YKnO>4oT*fL1sTH4YLL+hf+8lY!6y4Qk#G!I`<%0 zHcBvzwKnbWMYa547#Dg@tuT<(*zq8D_s1mLpQ*DV3%mSZQsh6@f*jX_^SC?g#1tS_ zbaMJ(NWcz6=Pm%mjpQX^BSviF`*7HxW(N!O*#B^Il-JH zIs5QE_GJr&kUzp;yP^!3IxwlSwHW~2^E?-GIKp5lP{l*~%??0vjwKp(jsTGJ`Ut41 zJGKD-+z70$#TtuQm;}`=pm-K+E)5lKF?|vX!%!0*0agL5S=2&0`@wzBArYA`QMF3O z-(2mK%>!Zxq8NtU?Lj~}AFlhTX^43c;e%!e!{38YAaJv-0O&v-6u$&#S7BWHD2nlT zA7ZUhVxN(+0|^0L)`ECo5l;YU!uFo)#q9M(+dWC{D1d&}WfaqqF^GS%h^Viu5tOLDlo-VoxbXdy!l>VR({ian5h*At>dW=*b&U-~;)mT-*CO*{W3hj7Eub- zm#u|QTgGj1Mn25Xu)tQ9V;R9|yCAO-0DW}DFA8fwQ?hEu_)o0bZfm3ba=eSBSXop5 z-dM^J!4Hd;PqJ*_$a0URxE=S)WGYgi4UY0&50SY3%vf$NMgatyJAre+)>#z|CnXWi zlZblN@Nf*^J!BXT^^<5D{kE0Hqp9tmS+vV@OD+x;7oh`n2#TT4 zf@1pbx=u`V;7hueSf@279+I2=6Thil|6_2Kg7~YRfv!)tRxJT!vP6|D7EW5=og*wB zq-0x2iOgfmudm`J%X1bTBem$*#!Hk^u@0rc|9_8t;KGnQi1 zQVGoV5BBFJiH5q-%pVhH4)Adb?ak&GJ&sM1Q(q1yL4W#c8N;C1HsCL^?GwXis$plxK)!RN-Cd&X*e6kgNezE9T_fynriY#UeaWEg$=4jG2 zt>G$qRBLzGjvT-Z-HhJI3}$??+44L=k&Gc3@H+C%E6v}NPxS15eP?|*j*`ida?(*^ zIO@{=ZcQ~QsvWJPKVOvOqnKOLgT4feyUg`q|TSqA~4e<9Iv}IT|eY9y7~tl-Y!a0 zNKv<^Z6DXD@vjBgNvO+Z%j;iQOuYR^ANB&#l3fyRy^d+hc;hr}C1mvTRoaDBLnYw< z-e6gvOqS?EDWhv=&8wtGKv++GP-Bnm7q&uDMrN;|9RlBucLX=O*+t8v#S0p5XChn- zx5;TCSFH3x>S}7QgcQn8ckKMDZKUJ|qkscCIyK9{!JbMgh>45;VVVOF6A)P%F5WuBS0~ptXiz|_+3{o1E?h`1uO4P^%mqK%w35v3Su_vMOb1c+pwCqpc$+b(oBEy7*0YZvnlYvGZv3HdS$}Wi=43<+* zJW9sD$)INbeeB+A1}k5qy;8|Zx;%P)5pYydQP#8(rU4|5eK_D%y#%LtY&`lRJ{)9v zV2wnj%IVl{*E;oKuT0_NfLeSKvEp#qhxKHk(&g1>^sMt-q{Siix-ZJ;X(xM5Vwm@$F$K;CT3nKg-&534Vi%HJO*R1lmNd;R?XG(5uonrdR)503`8g=emOEOL zKnbt!L&Whbk~izh+C5&$WIs46&6GtQBmX{9XF&C)6F78m0ALidAW0juo+w#faG)x7 zx#PUUG|lkaUSgaT;B??9QvHy(qDys;9<%rcq2#bxvh_N|g z{lMN-k*bMLkS;*SgJ$S0(WK0Au$Re>)So9=4)!eM17ue_B3b6F6EcHIqhXvSeVQ&&X=& z4`DZGy9&1vANUgq`P^?}yrNQ#id!ocVrfE-6;$s89b%LQ;=$)@f$ z*Fo#XM2Q;MEM{0Z%21fh8v#Pz$pB~!MuLqBprCQCa8zg<5bR_Jrdq>(8>T_k2p}48 z8(UtIVXT_M1SEUrdyZ6`_0JN{`A?4?OKwy&OIMr;mYm4M%mIfyb^)R-SBa{(>u0iA zqMlMG$KcGsd%1>lF(yXVfQS$I%23gTZ3zUF8PpsL5CG3se&TKNoZUFt#{UE(M$(Yl zl;Y=q{x5)K?!ULgFHwdL0Wi^l##sLqK+ztSsV*Bqa_*PwaixIfSb*PcCFpf>-DJoJ zYi|m`IvS+eeo Evzu3Q~*cyg1UZee9y}@twNXr4#M`hF!SH7(yCJDJel} zq~TlRz2}^L&))m{ZwETV`>wT~=lRtN`a4kU39cWxe%TS8mj8>*Tuhz# zp>J5rX$E7Xph0zc(s^66bx7n`_csdKa#}5vnyx4+d1UM9YJ73BZ--I@->t-;0(#GF zNA$44&9CTNf6HAwVf+1I3+<^nJ_ut)jdw{zCHb?yz-^Rj;KT)^t+Dy)__py1?34US zCKuogKDjehtL?S{rcg&>CPim3cV(bFv&Ds(UVmR3?x8;5J(A}K04b{({{CzOP-dRk z%_pgbTD}Qy?u!2(to2`=9$<5x|Is!oQ}(wH4fRt=DS*a}HMn{I?>lVpU+>*OgVMF# z{Rc#Wz{2t76EMkw?zGP5@~j>VnA5nFf>nJ>d^tC^5K%Oe2ca9|`LWxxwf6cCF#hz# z{``*?ifAuc+Z<6dBUmT+Q|4Ra`CuS(b#W`Ea{qQ?s!+4E$(6n8iv((Wi$pn}^5#dnp6vm+FF`4!64lI&Yf8Rds3ud-xg z=TxBV+4BUfgb*k)Uj+xDvZkH<_3w+y(}%y$-IeZer`$Bpf?4a*<~i3{+k~kFzgrl; z&mK#;Bh)-J1h^ZwwyizjRh52%ZJMb^s=e9~Tuk z{ZbzaUV%@EuKa)!tnd2caJ)iIX2xj`x|+c3vJ2*EtoE-dPDA9O{J*A6<^k?P^(!5f zZ2(69x)5Tf?y$&T;E6nO176og@K7grKp#Nk0}!hSG^LOa)* zy}R=NrM`?akP6RU5<(VzuP?s|OYh78S}))u^S)})B(UHePn$&61DAY9s_)h5Eqn#y(BNbznW;|AzL^y~_YYp~b) zu*Za>3;?2rnl1~I4D&4~D|R0UI$LZB#)ChM)kYLJ;ffSr0)vm+tbJ>9BVfo3g%Tn~OpcI<4@ zTH=hk=4^T_Z3p?eY1m^EnlPi=xh?`L;@fX(tfx4nEEoHSSz%UsBPe6`5-dnYjWl!K zb(Wo#O`rPw&!_T#0AK><=O0VZpbCYP+%^i{iX}#ts*x+!umY1LJdPX6V+m%q`5&w4 z!NH(WyO9z0cI6};PMEX4d9 zvMlW(^WDQY`f>o-`I#p28l6K)cwb6ihlhPG<(|R^t}gbn&o`I6G}=@`cy1dsP3Sw> z(T6E0h#PYmPvk8| zlCH@xwoGPa|C=}C#uc=zW*$*f?JC@HW?Bed^#RWo#F@NLS*4#kAFp!5Dy=Ar3(5`x z6~7PQhc)8YKfFE_PvcVw^S_G+Wh^{}l2lIV@B5`c(3XF5k;rr@4h1H7g5B-pA)9bs zKsr5^^BNa~?>`)#67f93TuU_HJ2|z&g8ytfjL`Ai%$6Lf;mGQI8j^URR`TT@4gz4< zUGv~z_>`jJ3sxqPlct`_#KTq8RBgAO>J}0D;E~~**j%UNEvnQ#p_dbu11sxQoXV=I z?JN3Y?E1#J?O-GPcnLVyvSI4KZA)%o#?b=r;2L;r#2)EzX*-1uAJBFOV4n0brK33v zbXKB7tFcOWX@d*|*7s{?t|xWud0u_btSMBQZ*;@gA7)ZWT3sdAqxw>< zkyj)u1o);D!kw}Xyj@P;Q)prar?lwV4=~E@0)Q%H=JP+%5OPF&3pLh6P40=%^SFWm z96bTfk855X9X&ca-T6e#}{1 z*8+@JeOXJexn_b72@9nP9}dTsIy_p3%!Xbo3>VjbPx7!FM|Y6tk}nRF`G*(U2{uJg zHd%v26x}_KHGObscL;{wHLwtJ*-`_EE@-I!1|v*N>yBdSBQTRNMJ_u=(BVi2{pRHm zfT^H|87Y?5m=>=Cn8D@Dd276H5P+==m3=oNb9`zo#~6z&zZR$$qI&@JI^nZ8Q>PK& z+-#!WV*bMy0xK-R-z@+6RELK^LUdjONJwb_I$mi7PmpXd54`4gbF{4QpC6GZWj-(a zdm7;nzn5}=uWH9Jry9H@v7D+jA2uxJcUYEk11C-(5#ae8r%DZ4v7t;9f7@gIf%Z}n zNEb=<-4rAf$Xl{*XGrLGh6YS$uhTjGQuP1TDura&xR_5YSo^1ts6tIgMwO8v}|o3eZtW_V)?*kO*)T!_w5!vvskR;zOW z*;Hb`*y7<(Eo`y1{#<*}u|7ozKn%J-+&vFwje86p;7iW~T~emW4q&iF?Z7e_4r4q1 zw($C=%SunA+rJ39`mcpCS3t4k4EnSXA<(r+wic>bkYaz}G7D{7je*XAin;*+{^aNJ zC*W-7FZTg+>Kv%8KkjOo5`syB%&n79n!8}ma|lKHG=k1$eqyWf#V|qm?7xPdG-d9_ z8p|R)3f_U=ApV59X0hCPy}o*z%zuL448JpcGk{wYEr6C8v z)`TyQ#_9paBgSVtQ#EdkA|;v{Cg7Drf^0mtCbah89GwG-CxVG;6ouL45lt7G4tjBv zfKJP~L|X`SVA^(|Tf^`2P}=w;dM%;qu&@7a0K{;KSk>xv0FZ!@wbJe9!qNo@GotDm zEE3A@{#5tQC}r{JB@Ymwp-(w|3cB0xvNOZu2CByM!Bddtbw6vYxiqo5hdrdOGzzpfBi)qBgirR^=^GA!osE-1=ClF zn`EThy0Zw&|%N%dOeHMCiN6fQn-tOE?9gxF=I70)J^-de~X18UJq zeXI9iE>G^+Sbdb^c{R{)pw$FZ`?ybNCm}sOjGhQL7Vdi$YOkq+Vs^1&d4gmN*J)PSD4SC;BqM;SC6Aau=DK@w*fvIL;-&&gNtI z;sencc96ChANGU}tN!scNPvk-_yHQ@$h5~`5%_NC@aS(4LJl9TQ>sDBj^Le3p0;&M zZw1crqTg+r-(H>I%cLCFE+Z)gJCer@oUod>dhqq<6RgP*x8r9y?Qf?DoqP*$I#VuB zqCp_f0F&B&nL!#xi6tq-pz}3kR@Lyq{zY^JM&$%m`8d}_?_=CG*_60f zB=`HF{; zGth4c(!n%htvV_S7=T=A3R&&*Th6Xdr)2L%f$&7sGiCsjOO(xlcBli#UKg$64BK`P8#)=L zbq33O5LU~Q&&W}r5U*%?0eTAw-y@<@%f>E=B*PEYVp?PQSK8U^leLb+X5_)ZzB}1s zrl46g&&wbzpka1dShM-Wax|-n7Bz8KSI?0hIi^#1P$mvxRNsX_%ZsZTgZd|&q*iFJ zB%fuws68>LMuS$;56{#{q*Q!QU)aR1u8lI(V!k}Gaw|VWc-z5}!{RM1t(w^<-^!h< zZ}aBHM;d;39>o9e-x8!z5ZdB6G`K)s{Kl2q5wh^s5)PeXBj1LqcD z-ET@lU`&z%QyOCn&g`8Um(dJrG&mZ?SOpHoW69NcsZs*Pi1<6GS!?%;BtEWJoc@YC zzq28+c$!Y2G3CQUZTa_|3ADvR?fyBoi zU1p>ZM7{o6%g5Quhowf>B43c>JaO?B+Nd6BPVL_vv!bGE zC(lb4``5W*`4U&4*d>isii>GmDCp^FR_h@&=mVy^em)N86ln$h?^k9^FtxIb0ZIeL zthw@ps$$N-lQ&Pn^Cj@*VF(m=<(}&fOZ`k_tv1m9sfMs%PCqlVR=C@Eci)wChHRJ{ zvFz@taGEgDFu!884(d?qSab9pZLX)bfJ4T20%2n+CmfaQPW2l7XZtc{dS3fo$~^bi zLo0t$VD$-3ikQ(Loai`U@Iy*F7m}H+vwV?XBkrsuM|xK4E5nj&6a0#A9n&bZ?&V!L zmTFf2WOSc zrtuWyPS=&6E$d))^yi+DIO7&I|GH$nq2Qo>SBhraDRcDa-V51ivHRxxub&NI->%kK zA4>~1HZv)lTYs*BZlx(ORXB63DR2qm8f$4w7~gC+a+1@JhZc6foWbuoOIKLm!FXRZ zwGD^}HqYU_7EpS`xO);`UW&1P#fbP5Y6cQB8%Q8K)FxV3{q^CKrfMmomQ-(c7%B;T zE^n1Kf!IvrI4MqB#>w9PXX0UlC`Iy8rf*!l^j)#Lxwc8>^MGg6$5zvr5j#i4nedy_ zrsTM@6pNzd5#tL*LJp-VV2HDxw80$>X`Xpl{?zD;FXg$Kc8F*BsmwC$;gt_B03qvv#ZVpiqjwttc8htYACr( z>>sC~#|+%IqqS+GB(jcI+=*SQ4FU`kb7#+OXnbbX+4SMSD55|qBRHtekY!z;aUrBS zBvDRh=+f->ugDXoNGxooU@H!V=PAj(25L0W);(5jXONn$dxGa$WILCktdT00c|MYI zkViO)(bW?W!qZRpNd*qa-ZH=N>^dZwO^C8S1?%nC48HlV)R#z8Z#$5IbkNDS?dD!y z!#JF8gKT_J)?$(TOSo#?xqdjj=+1aa(Ny8xW6kt#LpSXNmPp5AZJ+rX*+y!;Zf@&dVGGWM`oSgVTV z3Wx^pDD&1h>#f|4BqCF&A{}!CssW-;Y6(qx$<>J^Ml&Q+D*k5mQ&8I>uG?G-wZ_A^ z*<+FSySq9$yL4tNU^r~va6`_EpwSr|Z=TfMje4fSr#P+(+%E^P6>e&H-O-xiZX2Ea z5+7uOTEa!S+|Sj5i|%&`Q}x%k%KsontUBId72|NkeZc={{Dap^piX#StAorIv4(_e zrOq^4?yKg=W9_J1)pbx2e>VMUbu;2%qn_1g4ZU20l1K{xneKQXy6m*6HchuY`x77>Jp|-uFoY|G2I*hBJ zEf+ktxF%yR4Rr6C#c$O}vvnz%MyfP`B#z>uBJi3$YyQ+Q4kkai3#`g(-3he@72d%(Fg|7w$EiWx2U}eg>0>j zpEBG{(n#B?WjO(mnWcs5CuAW+sk|7XK5=~lSe{LVGI_-?ZX6DU51P#DGf7=0j$5_; zBVpAuIo5XK?Li^xg1HH&z-+^FkBQNhH5~2ZiL}ERH=`+eu!ft;k8(0uoy;*bPiXq& zWYy+y_6!JcKx*oQJ82~_{$yiAbe3m*v0g_s>-TH!;&_&?zpY*Yfx*~Qj}{b(7by+{ z-o)F_<`6&ton%)iI%6fjarU9trss@?o@x{gO57BRb)oTAB(um%E2-xh0aO#Ub=N@d zirv@D;*;*%QiWn1S1kKS1Q3_>ndSq~hf3R4QCcT=SKcQ6jLK*Xvl^c)vSjGoZjj}F z!se-`Ls>|Py(Y{jUj{iAYDyV;r&s<{I(4d!6)9XLSSifcZ}iczQlFFJdZMLu{4L~C zMGyxFrLrr{Fn@fdv35F78`mBM2NO~ytq8QH*O{X;;t&1o8?0VpX$@6Z zCpg%~ino`{z)7lI!pH513F4klK}6>#CMn|U*tWl}N}C9rawQeDPCLLI@?5iC z1&VJMJX})gVSVydQRoVo7(#iNkSSPj$Nq;16)oHNByE5R7p;26pZn|os5hdVxK~DY z0I+pI`SiPz^Gp+W6lh?K380zIYq5OK)_bPX(|0bhZsR?268B1Ho!9m&-dYGoW3K7# zT)|F$+aK{xz8?%f@MiN2X~MS)R2}*NwZj?c6klXS&WSi9iLCS%nF8CV3i*c%^=8V0 zRM?{%^8Qvl{#dUVRb&%u*FXB`j`AdQ6-fvThs(8gAU0#CvqXLty_Z;z9hQWquhlE# z-HK0M^PD)iQlY3gf^I^lVKR-rkZ^WV69ikYwtAD<4Si;k2CDrdt=rJGz5`#iCYxV> zuDP6kFKK`}Zn26?{u3vou*LnlE2GIC;g2(Go?rr%^wO>;;*V!yG1Xo;;Vm?@+=dp2 z7T?M~h+TN4UNW?;t9vhOO4DYsh#+3f(ntl8o*G-d1oSP`TM4n)#VbrLL?l)A=_>wl z@#Z>}x+;q?5?R^hwi=-7Sr_If7}Hv3n0~n*ENFf=yYEnt*M36IoYOj#ujlDLQkm4C zILhonfr2IHULTor$faB|;{sn!Gb5~@mCc%&0jA;DJfNcC4~4(@QBOF`Db2K;W4X&% zCITw=K7IJYl(&(Dk+xBFB2gL%Bz8)fDsaNydwG~B1c#`K1Y|r6h6;w!(Sn@Sg%8a6 z+tIo)A5+fR3JuB0?(j@Z`JY+bHLWIrsHcZ~>tj${whar5)k1r;Ee$U&#<1A=0{Z$Q zi#ysWaMu^i>-EYqWe_A~TJ|9P`3lF5hvt^ofrrKBzjl>wsrG__l_cDUB{c{F!j#^L z@F6eCsK-MuWt6u(^L;3eEyW^W=Qhd6Yi8*1pE&T3r$l+L+f?xG$v;J5Nvg85VqYwo zkoYxPSM*ajm78yQyZF-i>IXNF|SnA5S#{cAm{!sRx9&Tamfe2)gF-ZUxzSBnHr5hI}q zzW~u#jwJ~b=93N%;$MfdZNo(PmN!>4;Ks!XTgEGzV%!_S?;K0KRdL|Uw!)?#vOoG1 zww}EQa?Z|8sO^ek$3Ll&wU39DNb@RON=dP`>0p*NBKlBsc%axv*?aTp0HLrg%)|<0A#8Vj%sIBv{CPC^eaC9 z{Y>L#z+SO57&1GH#E{1+Qj3_#1wpQ*<5>d^|5Ub+C`SksOGn$pIx4-z8ZPX35>wOt zfnYYQrfBX5aV=)(YjQD=G~k5F8s6UCOgF*0U8Apa;rLZ-%~N*dYHz6{p!S>Z#R~Pl zsnH@DwAj`h*<6^ZE#UQ9pTU&ll|kMu`ua-yCOV?zO25{794aOds@YE-Jp?$a}?rCM!Im?b(1{!3=$?G92#i zSscdv^33AQ=F>-(7Pw-D?&QaF30qDQkOC?3Zl6_}AUwfZ>|HOd2K2_pRpmL?DP4%b zsB(H$illJra?C;zih}>*o2@Ex@RogF<2XUrUl6OL0sYukLp7+Yb?FKdPiN@jh+?_OU8cy>n7f>f55ZZ%EdQ+j5Avu zC^;5ycWW3saml=>T7LseNWxOt^3*zQSdY`Vmfj3T^G?_j_@qVI7qxbsXG-8rbenu`wiBGJHQAOgg*J!xZ7i!qmI8^L zS$U=ro{uq@cokIcN^3#zOp8BVB)sS=03WAhBvCD={JC^K#*nh%s_CkZTuAZeacEElKH6esgNDpTjKOmz-q^RT*+MVmjdTUqT`D9JZwERj4(Le!8FMT|17s3 zCjwdFYEj6;t?;hA!X@QpU&>m&k(sr8p0ERJH#3LNhBUlL+^pxPpQ)%8zmBhs&W3cf z>B1^VwA6^GAzB#=yn$uSxW$&5Xt@JhiDvBGCjVf{wy$Umzx^6LDZ64>J*TU1sE*Vc zehx(zgdafC?ljmr+)$o+;a~jth1j^LlP9A?&0}$7c6mqwOQ8m_WichuYU4Bh=sDPd*n4#it<%Fdf}l} zs#(0tSuIXu-5NK!o6f(u$|We5Yv}Jg^W^+m_2Q>}Q&ZKp84J&^qgJSJ^Dc&n{iweP zTj(WqJUsHxVA^-dk3mUW*WyK*e$qw6} z^tFx)wZ=(}tQP1Te|t`0tLAK@MdPC&18l28>p_(3>~Gl{zUzehiU=LOPX&e}?8)3x z%<^%KW9a0!sREY;?XMm*yhohYEykM#-oB?UuTsh6P%_6bb)7M%26P|nW*zsXpbn?Z zoOtz5dyrvVkr%}+SD!+Ou=dfPu5GK3J1tz7lbluC^yt-d(UB>Ub`se0{H zZ8cFKE>v+vJ@Jr^@J}cDAQ10h!xt(m4#!B6NqZsT6F4cg4;+2GrPgz`8#(kENCtDr ze6o)toKtG29TteboNkWV#VYV(onBPguTOp3>F+fGJL-C?Bm>Z=F7aHG4g*yvX5c`%~rI3 z`*|W>hKH)kj;q7iE@0Z&SHzx)35s zzzx)9zvS0q0ENLUk4lTi6C>&6>Qf@c6T{r-`9n*Am-lFMj0uLjiGi*~e$G-qq~z@k z{26Lx7j`zMt04x29*9G1~^Kp(*PRxN9XjLUCJ`cZ$2m#ZcMzg(kf~s}(An=x|b0*(J zwZj7zXeVM;&l@w2{-gDYL%AfA2wDE^lKn4LsNW_q6gmp}<=p@GJNhq$<411bSsZ;Y zbK^g-=>Po*c_zTlj$v_6{6i+jA2+kHfKciHNW)#h)i2899jHwUv|yrwb_J=Z%Wp2% z#jYJtmrI~}#CZS=&8aE$sr`&&QJn*>jKp4gHV*Bs1A6%ggH4pUIEifRK)T=J4L4|m=AudriNDWa2RQ$v|xL#r%{m#8_z-g=MdSy%wy#IWtEQdNJ zvCHvGFt4ICm~JRrAL`(M7ZHxF!4mtphm+fvi-@+^4 z%5?>VWHAsoBIW?|vb)OT4cKD#xMI5%m+-fD$YZ8N!()N0<9pY{+0$X{`C!K%&H%5e z19IEX;S_uv@4ve1*a7_zFvT6$gM*JjI5Poe9HPw^e(2=%tPMQ;4Wtz}#S>W{%} z?*jF&0NPAAJo+#CbiMiXCF^AC=k=yN80#^HfWoW8(-oSW3kgcxMlt`3X=xo0CtxfsEBpD}t9ApUg z{ytBE=}e9y(2ocOih7Qe|H#Qp$6>E}5#UA4DBtU0#BdCFa2|ehLf|vRLt5#ovu#kJ zp1V``V#$XZpa>fD20V3m0V}k%$REgQp4=B&K-4|soAw-ml(F)buu=x&vRa!4&YNIR zI=^7HM45ZNn?UA3Moa=oAtpEmS9?5ns96bG-I!?tbnIO{Ax;xFatmfidK-=v@NzatD37k~OxDnwFIE)GBH;~R`60x7Qcyw!(9 z@p;VRF;dT-zL4KGXubc_Y-eV^uyIQNe16;e`0|JK&TdJGXTes<7dA`Jp6!bq4m^pyQ0A0o*r$8JI-Aqvb3VJMxcP^WX=(E>xhY_e-wn)q;Cr!8JlY7H z2FNtPv0(Xl8KJ#@L-^?C^UpwIOlOGtm&7Ro%(3`StQADH%6-&Vd%+7pR+8#-9}+3Y z=ecn4oiA5>`6m!sKd%PRm%Dwuy2d8HXr`GOzJ#$|lz5<7vR4Sb|2<}3L;m+th}Nq= zn#cQ)K;OkHZd+CM;~5m;lL+3JP5WgDneW+H`k9M0C=Ou-L&92GE?rPvW{b72P2^vCy)t$Tv~Jd1}{E7gb7FwsGqi!}Po1F=eZgWP&s) z7_wE%idQJP;wtXV#8=>}?_?PY2P+Eicl!ABQX@Nz|N3|}2@|cc5KT|HVMFsdo(n-` zy1>#m_S6X&73BiH<#&rPb>P!NW>;|}3}Mjz2CvYv&WgM+!>_$>(y6m1n9)@5y=^fO z%AI_C8~6CyxfHK=#XrMo5mlg?l{8IkHn16eeeOZg&NcNU7Ws&yHG1Za%(QLIS4KSp z@Hv*e?28L-A2APr;)?0h(4=n<8Ep&u)HQNsYC>E^yy zN~>_-UN|(HmCdS~s-x-c5@=Sq| zM&7`^?S?^>#ycD-Zi&+$IR;9rfPQa!RZi{&rr z2IVOkF34K;f_%8;1vPx!RbxQ{JfI!y{wQ(RE5}P1OK#J%^^59vm>l%mY8 zvNYucXDR3z%q8w^Q6ztO0srYa)u_V1Ro<_OJOZt$q8-8a@yDZmO8W`he&4Y^dqS@) z#0V5<59*&!@4Y=@!w)sEdr+-~bCtYhL+lqC!JC1+5t9CEQN7_ij*9BE|Bamjxt6nu zQpI+*p3pD~o6 zyR#!6kf&4pZ+ZFmHYoK|~Z2jqj)v?$@SAEh=4Nc~m=GQ<;wfWlbhhG_8 z2`E!c^^)V|q97+oxZEO+q9+BdQzd#2_LwIG6N<}K3N)4^Xj~Y4gm73lix@~KkTNLl z&0}qk*;`f4Ld(Lmi^?S8O?Z*UT^;*cUA4V&6)G6Qd2J*v_Z63p7UJZc5_=3{ZayiS zwWvDT-JZNx)-FkrA=4(+%|i%Z4dT+EBp3;tfUi~{IH2zSrAOlOFQzc@>m#3{g$Or+ zVe!oDVLL|Qvx`O0TBxK(pcF%nrF4+5tG8}Ol#OSmL@_CZ5*NPU#rkCXPR)F0tZDF_ zFoUsC;6j0*5O&yO8SM##IK>|de`M8dB$W#Ddt`bQt^%`z%ygcXmb!h~Wf_P+y{+Cv?=47S$}{D2$v@a+{Vrw*^l{p`FZ(racHorM3}0)Tg9m_v9^ zr=5%X!Oa+%CNFPpzueaiLy>nNZ}ksI}u}uqLp!S3p}5;qPx#IB?+xELCmL#Ys$WSgTffOwI{0A}G>d zIyql>IJGKD8JO*=Gqmy+Z9tZAO?~wt8jV;N@+&HXq7TqP+tqR-%~1i$7oIV_WEdXeB7 z%}>yA?^ap}Y3tG9QqGS>(!7wexS#@20_F$Oq6LJ~SAW z$Uw~m3i(|`LpzVRmE!LAP0Fr%OsKQ+q70509OJ26I}x82hRL({Jda#LU0>7^-Zw%A zrzBkAa|KD^%4kL1okb~F=*2oLbVlp+v5g`joHj6+!5wjN@;7~uBC4g!&T-Ksw0k4) zuFUj)9s2N$fY$A(QetL4%4#12S<@|1>B&T?T3(U9pYiLqSWxtx4M>P6AyEebydKb! zffCc9iTzjzj#JjdJ{M7j*9Cz_B?ie~Y(T_U{b81qR-!+hM@r}bi4jZKvZG}n7pFG< z3pA!c(G%6k)$Z|W)afH5AXPAo`kR4o=yg<*?6G4zmw{7aH6)r9Txd5q zT3TpZdwTMO<)9V(hV&&hpgMC^KM*d+$*&~AJnkR-X6n(05wJ=04)%)fs<5QNsv)CX z|F66CJzt!L)4 z*^O9kIsj*tj4aJ%5mT;v8EtG8gYOegR8qTnKCizt1Pjag#)!DHrAYXXStb)66@Cwee#V%^Jct7P+RcI7G%G0h@ zPmV8FG$qcNYXvgygDl>(^*{!*H*1`x*+mSX7{!HJFz#IVAPWt6y4BZ>1Thg!oC9Jl zUv?ipmUXIsn^iPvDqJLFU0u+0h+F=4V*S;hX43yT8T}k24Ix<2qDEM9q@_FT z;p0ag%LR6ZV9VZ=Yn`j$s6Fw+G@UZu8NyW#j8|YmU7Qd~M)dBGE>gInhoot=L22wD zsmOAM2u={Xnm|3q63+)oGgYQ5tf*PV_n=!G#gTn@Q*}%a>R77KQZ`Ae5XG_@Srrhu z9POeW!EXBYzz^^*D({lpM6D~!H*ZTX{qad>7m^Yj9HqRlB}1m=MCd!=nO`qT_^gP% zpn>6l>A0u9KLEMAhp=0(ccy`~g>cb?R|NxQyYPh0kqVO&t+Lea%VgWh$cVvwH9YlX zl8~~%M9r2H{)ab&f|v|w%`N!i3`mXgkuR{M&x4$A*Up8$xW~h8^3l0Upn{m+A%^2! zd4a*#?%8q4u6ag-1B9|AVTn3L(2~*`4vWGpFtK=#dS+H-tIUi`5+cX(oyFg)4#CXU zsRiZcGwX)15Ui+aEW-9HhWaM?Dlcg}(SVx%S_S2qVIXzUFb#8gL2im=@_4rHM*0Ls zc?b!D@5}HDbnT8O$BW1ZmutbrC4xT||2jbJV!mfE>U;V^3_b8pOZ8(((vP$}q;E}R zt;$a$ChKCwoHe!RSnzD?9$r5{;No#JB)rzve6e(xSv2;L6dfzTU}qy-5xoU<%_eq+ z3(rsBDRv&zwms>~^>A7NURT-O`ZZ<^U0PhsTX(ZG;exR7HBh_dH^)CeNIiR822yts zPA{OA){_oZeZFS5 z@lCsWNnzI0ecC8kVQW2ag~1~&*NtSo^Txh5Q$E;#z`xl8SY#fIu3KY3g z(q?_x!y_U|@7n=jP2Fv2zM1cAF-kOwo45|KVS71z%`8m^@uhL0{U-Fy67&qW&gh~a zXn@cj*{jb0OtV*-2AJ(AjrK_p$aS)a5fkXNT&0N-q$x4FxBOJJQ?IfE<*=TOjc_P1 zhk>-Sb`Y;h-U34Slp4eo@uEBNq66`OHroJ(vQq&_QM4z9Om={vFF_68GSW7XgP|mw zJOgQCWzOl*2c1DnUh$b3?+{iVi|3p%xp)gBTV?p-Q? z7I%%CkGe%ve!*+w(WVUsA#|S(v|i+h5oP4FH~lc<#0g0AHmfVx=I?kYwJd;inv2x< zvPAjQT{>Q~k^H|#AVak8o@m`MW$%S%-tu>OmfYlHI?l*eem9oXkt>SKF9RW81L~*D z#6py(#^0_dYg>4pYCQT#EhPotWGN-DN(ZWNnv&!X@1`v_Ni%}9X|3d1Pmyk|=kt3l z$IYCblyQ=Cq#~_rhg$xhnYWi9el}TPDv_>o#07p(+jq(DgKC@B*y$$3N|{$W27v)6 z#)n{5Mi-q%3cBsV5H=M2*P(#uCL@GNoU7>;8p<6@zWkO(wy(+f#*=<8l=r?b2^-PR zAM~UMWVv?SqLTFac8gjjkYN%^5b2Qg5(Y9%F}B{19ZIG=r(72NVEJuv((%?bgQ~X>%Bx|P1rBtf zd#A&`KJ;VcKS4U>-ZEKh-Ncd41ZIx9=ueMfobmE!cTu5pL$qkm_3+IJomKm{05VU# zaF}*XPYIcS>U;fl*vFNA>|1VJ*<-u`B1QwDGBtiQhN=V6~=gz(J4r0W0q zf1m4U2>3!}x64JZPlu^%vjjx`Qt)ojJz~U6EPD{^|BCCct?i$F9J4Jj+uH9h@9RIH z?xUL~0dKGn_(@#VwWslrw9W) z1f){_Wcd1Gxco+ywM5Hd>d!y`gROiGnlKQo&8vBsJHt-Fh_^>pwRpg)lFh=U)C z_YR4x*9v?BeD(n;gpcYcU^eAl_njO;q(H9Vowq5KuaA2~f0geo9JjcsfPod{tvp=1 z>=CeBkJ@ z{V%Neb0Y1RWX5{n%zv%kDn8ORZ}OTj2dkB=>D%pQz|LgX0&(Q8EAYI21t5OTF8r!# znVoYd3h|3uOuxQZ5AVYWOK3UDj=!Syn?(WBjD~LG%F+sZjevK|K963N+5PFYE;NP& z)RsuwA`o8+isSEdfV@MIcGP9V#1}QqC*b$u6K7hJ*I)kJfXX;WP6+>|8Jf@Mf9@`( zZ^_b2y^c2gak(Kac0X?m+zY>v8*m67GDI)n83%9>dM#3WfPjc%Pr#bl?3(qj$Fc1f zT&db!G|18GF=bWTSjX+B#DKoKzzsxX9|I(+RbHSUHIu8fZ1pExWegn05kInas50j>{4nZuxhsrb#XH!|E9zDI=h|#riIzIOHC< zx81dU1!RaNmH#MAN2Mc}LvURP@e3+ljDFbt_v8NY?4i8oWMQw|9C{z{a!pVZ_@cmZ zl!-TlnYeAQi_@o^dM?n6I#lXRDy$-qGOGhcKfDI4#r5uzy*U7Y+zu*Hq(TDtBtAWq z^^W+W<#f+^WL_06Z@Z(jSmQo9aiMv%{?-T}B(O-^}p{NCr zp~w_F#F#;G6Xp>CH*HS8{9(R%hHLLGDV8dDdim3LF-$`tWRK>~Dcwb0;K9cS1k1E| zG7TjX=NWqY=ie~Iriat#Ko#e7Ru`!9op^lkME!>K7EUWF)nlzNqU@rB`s&Luo1!icrGxoXDhu^RiXmk0W5J#KC4oK!5Ea+FYoHq;EF>X!Z;a%YODf@G}n?Erh0rK1#X*ySUybhc5zXrCU#9v$sJ&c-(~@fMx>JhFp%HYvC)v@Hl*k z;Q{;mdjDNs7-=7A62R%TZb5Ut(K14a?=*vT-lP=M#lv#lQ~teGrUOM)obm&MED;vr z)KM~l1PlyARIVUse3jaIs3fD#shxi5dCZ|)}Z<>H+k?5_afwzlXg3LR|!DqP3(DoQFiC3M2UZYjo z%kL=$vktMyFK2IeGO9+FXN^B?poi>-iXLT%CDa5mz{KhMjU%`W`?>ewqd{e+R(xyB zZTB5OYR;6|PPA}LI*7t*nH>H|F&JZj`Oi+9p`m8GDT)VDa9oT#8c^_SM}`FBn@qo2*6O$|~A4DG$xTeIq^x zDUufW?jQ8XGP^{TEMMp-1Y6Zd>Jz7#H*8DHC9JHXCSjq(1^&u*`_uA0=K(Ben$i(z z6~-vythFw_{eA{yN!%d7VCIfTp?2C08_U;nPhelJtwQjf3)9)Lpfis>H!GdyX5z@M zunv z{Ps7vZn*DgMx{!gUfp541IZ?HT-N*PshJ))Fy(3Txy0ob`Noox6y*|F+z4SpRf4!X zTs$&^SkN4Y{zY8Axkom48G}@H8EA6y*J*cnrws$*jzRK}dko$ZyT8gUOFgzf>fT`7 zD|6N7u*HNHb$$-qvyrO&&DP)_d~&%!@fA7lBxF|t!@jMcSRZZ#i$)3|bB>})j3z5g zD@nFOw{Sf9r#u6qZtF@$;IaYORrO07CY$cW<7kpPl!u!*1Kn-T(l;t@9GCC~t7eWR zj{U{KSak$QuQ)(!ww+D5IY@8Rhe5Q4Gn(RBcx3^shcAePC})3BIMkj=xr)2{F>Ja6 ziiUN?e>#>rTl2(e{NNTE`n9-^R>o5a-z*mgEV|`1ez}`?H_6=2h$e_53amYRF}3oY zN4t^x=zP7-va^Ch@*-*v0wQQ3eX(b*NQEp?oDSU$ra*RNAg@Am8>hD>hgY26#TwPU zO_Qj0MCsYrl(IMqqm}>1+k3}T{r~^}l`_g65pnFj5*1n5TO8xqPLU)svq?7D9D9Ug z9wQ+u<4{(}u}Vf{9%US4^Lw1$>+^oSKELt(=l5TKxa6GY^Xc(?JnpyK?Rpbl!exxh zIzcU;YAJmIZFD8NN=bxcj%p+3ljC2dUk%0lMZ_1qz;(gx5*Q12zKG04)oGw{0LJl) z#u&!DgkBP2{9-R9zDE)~2q)1L)FB@FjspqFU#h*B3C%6}{nZfwI45O^G<<)l^dR~(yGZ=x!Nx?}X`O-ALCGP4 zM#>^ZY&ut3zMg#{$YE~Q&}zL6sDXZzM|gh8Wno;zKq{vOPr!E5z{!+PD#c~A*}l9@ zZ_LBioF}Qjk+mg$->eHMu3o;I@&kyOxqV@N765qRZ^-`^PSRh0q9TX(Vqg0xg-)z} zSvSdhXTet9EJYseqI>Z=#MHG7R-yUWVf6fQkLy(d-4qWUVW7LqIqK~?fK#NdloAZX zO=k%ykI>cR_-@6HpLRd52*=F2)56t{3$Lx|shL;Yjc(q|&n`J-cIl$>AM>;Buu=!J zR%BcMk?P7Cn3dwxRy_yW2F<8NA!Sk@4CoTvldDBSv5Pmp+hBk zLAZVE!W_tPX?2u#CoAf}NDER$!H9Ogzc`*6A%3r3?eUeGSDl!etU-am13eF|E~9|B zZQ)-66nCK^NMbJRb73f(VDk=>cb0Yt@)#RTgmBYlU&G?(|KsI?=e7eFhp?SrrL_}j z5R#1`CV98`)|JwTk~o1QMZxmY@Gd?o_}8LAel4g>a@(!$tZKpDdkIPLX~b(}NvFU@ z;`I^>pPJlh&1R8m*BOFt3(GJ(M(7S@Hw4P-`rK8#F|%{N+}T;zx!WQBqvteY-$`bF$@ZgGz#p&co=jV#05YPCbIh3AeOQY_%n(TwN6jR?T_f zYQEEiV&D=KWiJzNbZns1X;~zDozxwzhDxYM6Eyy)4 zYpO<6f10rRw4LW>vi6!|g0ICTHKO{dnH|Z50R^&oKre*rY6-G>oWuTu6xFaRW25qo zb;A&@6JdCHjzmbW@`<2hvgq+n2glw7vPB8DG`@wY0}T7ZJ4&JyW_HLS)xYkWUcI2) zKYFYy%poO4){MQaCKEzWAV_FNc@_B9A6H1E6KjskJoMq8`@+DQ`%=T4k{x66aiA$~ zis_LC=s6D&ns~%PuI)CSy!rn3q`*N%&FSc?hnJCfMYONrtoN5ZLz-ukjX9JygD}29$+_d-0`6QK2mHtpXPH zC7?m{7i85MGG@fWa`}G+#~zIS;Lct=sSmMjUCMU9U+*oGe3!EaY}vlOtLOZc9D}M_ zh%3OtnBiZM{);|#FRNRCs0H;lq*|^?V|k?El^Vd&ZOskDM```r)%BH!i$($Lf^YI6 zoHc_BojNIlpeUh4H!8aNr@mb#b}p|rWlsr~Sfp>jElopJai(_nQz+j~Efa=IPcBZv zH>o5yRE@S&Q-&X@=^a_!<f6`K`(xBvFvF)hdybE5d5bgbC^ZY-8Nj7Olz zX*V`w73mt2k23qbWwRxD>?g5>=C-d%&J#5j@GZs9m~Rv0!fmC9HIbKGnQP1(YfxAA zp)y0gHlfR3z_pwMJN;w{-re{BwH*STLhDNuqfj?6Xkyu8IDIA%nW6nHVQ z^0*}6sz9Ku4;9ayo5(g=Z4q=6s&#>-X&3C zYv2G@2+1b=)sU2GUVCd2*b}qw>aMm3z}0Og+k?e%0u@;Ccor_W`n70UfeG?a1AVLl zp9aUmqI(bEfFMNkP&nzN5^GpA_s0$B+u%p2AnwY3Ktma zf!?kdNlkJ2DfQ%c+~~y8k1K^j_LFbioj)Bd340hx8K`*d-annZ4&MGnUJjExpgZA< zaY39d5H(d@3q(4lOm-ud)r7IjtgS>QMdi7n)k?Kb34QRew}qlW$Nusw@KRUDZ4^|> zPyBBe+kj1Uh!SB#KCiT3;8a&iAj^S3)24kimj@}JSCiD?sct#bhQiFgy~RxgDafKeqB-QmdWhG9AP#E zkj!Q7WAv5JIk3u*!bwWQ7RlQZzxQ~4M`opKkQx;dd@4s#N`z)-$FZgG@$|jy_-$}W zp^1|tY?vfL;Y5Mg7}u#!0HsnBpHn-M=aFk%gqk$R%UMUTU|w-e0IouM(MFUFl}m1M z_COY~;#b$fM><*s6NI7`lg5?CAzY582Yu=lQ&p2y$1b0QINjQ`mnjp`Npa*)Hc;@W zBQV7NTKE8SB7CC40t;CL^Y9d)u0>rqE2yvLd|$(h%zisZ>-Yp|qM^e{o<_}VOJQ|?_K@5UVUi4VM z)u>KXqLs#?Jp$rV6 zkCXCUJy*D=FMHz8j5vO+vYt=sIcH0GrOD`24wvMYbb6NL`vsN;fD(l`%&VIyWHRR~ zD2*By302CIrQm>>>8*qKwZ~;){pV$?;7RR1^e{XajFUVlkb((o%fD1J(@7K!Wlq%D z6`dftVQNREa`frMHRqZBDAJ$APOVAbuJPg9<0!4Z6AH6Og6es36f26i7m*&`Zcpg~ zGase~C?3LiZVl0Nxum=hImHE(^+BBCbM^<+yZPH-7gM)rVkwlpAw1<*Jhds7djq3dkkgw7i|JVK5nIMRU!YM z?5_e2Zr;zF`3WqtH0UTTu2-lRTc3+scCtRnUC?Me)En9l^R$eKv9_fs>vaPNIp&mDT9WaKOt=aa+7W&B{i8L6MUQec_7W z{Z-Z2!Y!d^-kMFXf`4oxMf^)|yh6uf8F~k*fnPUF%_yW{xTj?FIfkbAHBkUyeEE6J zU9tMYfM}Bcs#l+2eHozJ0w1PHQ4IU=E8#em(1PBPh4NnAcW3mL{c}9xIQ{a3@3;MN zV)qUNc_UA{;z-#{ZxxC0eltn^Eg_mO>6}z4?j(y=&68(>q`0r%R-s!q*o|LOizs^D zfX`Uqg{3lns8^0af|ssGw5+EA#(<(36k#`1x?+Pf4_`MVt4A1pFU@`S?dTV?X zx|BVLaHtqC3^huH;pisVNb%tHJ~Q)?8(pgl9y7%YvAYIY2X(LkAn$R70S>Nsac zM&n)ja{!i1fzLnO0T5k%YJ4NXX6EcMcgt4HGgABybb=O1F&gzXTAsV9XFJ7mWFY3@ zxesQ+lt5E&+%W^nhSVyb4D@;K!6&;vy{UM(C+>Hx1ymRmkKTiU>QyuV^xbjX`s5I0 zSJqN=r5l{k*rvb?c23jkP#*@;WyJy+Z^krdI#^RB#$g<&`pGAaBe2{+P!2@_QkRzB z_c5uh;z*As-0t*7z-@Ct-!2_81t3+si>Y9UFKP~&9O2-TYx{4$;>_p90GyfJCqOrX z!_?qzzW}b614_uUVn8<6zdw)FStyFEMME5`0IS3{Xd$=M+;UV{0Tv+ zUThP>1t-}G83Z~^1s&-uh)qoQu@ubSE@! z;8}p1hKS8p3%6sR!*yH>_@Bkck6hRU*}Q>55?6TZ(yF5G4^JSoP+VFBHzEzaJvXli zIlQmCOO@SqDIr3>WaJqx8iC;Z#7okD%U0BY@U8sL5V)_}8$b=Wm<5lUExLxnWigVZ zUjz2@@qhoRJ)#4mwnNlW2N6UocpYqnp8+9&R<27v>#}81U)$YW;5qX@0~M$rW}j)z z{RH0idzi=+2z7CP@fsf3{?-U3pq%sKmlpWn(-i{NW8RUO+!791O||8#)8# zGpUo))#KoxvQ2Rwk4=9D0;gI&Kiua7{G<*BJzJC32OL9?7%R`~wyj#Q@z=+4>)e7w zKYld-*J7b!eTx+@KERe^Of%fU3GUYF&j)Zm1y&x`4ACz(N!rwU)!4G~-x(N8Ve}E~ zrGl7(A8R4WbZ0~nDz>l2B~6_25e!{JKIBqcjnZ7JPV*qUoxP=7yx!zTt_iExb}$R{ zSnagyFwE%N@|``JnYm_{l~A;ZXR^Pa zXjzhwArwJPl$845a|O8Y-TNukEbKn+5cas$S3US6OOcjXgq3ZIp^wK%<~M2tz9SP8 zbBRVOea765>MIzAj5@eKPv?(WEEtDBtoQ_90Ghn8uu}vSc~~|sb=;!^erLB--(VE)n(54y3?HD^#j%1!Hx)@vrrK~wmQdZ z4$@P6TcG;sH>p~-e%CAg4GHQ`Zd%JTvNmaew}tZkI|%i5_BRgAiI!9mz-V;>4w5o+ zDzg)H8$jhzZ<}6S&@KLw)UD9_ToPI*%NS)Xxh z;?83lMzTqq{RnBE`1eY7xk*X{>3Csq?G1SYpLalM4rpT4+}rg_CwY`HTAnF#n>OuLIJ!6NXxs||@)epE z>rfpu`As1NSx|COQ|(fh;y0f!L*~&mSP>To$#a*2+S{31+`hW@3nkqRk=*qJg~clq z>3$?Z^^2iS^RK1xB?9h)bv@L5Y&>!$aif~YFPN2(SWzcA;1JnfxRvwvIoyO0Bjl;Z z9U0O6%zw@7q&CWn&D?T!ID0}!P33sAoIRJeJMSSgoJ6>gemYrkqV;VoFr=&UKptz@ zEB+h~Akm$~HxMgrx(>uGpTpFV_PL8&jO2`YI@9WScp$Y~Gv-JAsStis`nmZW4D$Pn z7fMTahCi09J-M<|-dJ)bPZ6*mp(yD>#wS?HF1UKOrD_VS1-HDlA%i>D7fb5HtYk$s zRz#e?;iGgm(kJg_3s*Z|A8&6(9YrPWtV-Tv6#VZct)2LjCEf#Nvx)vr>cB@>f$EK5 zlKWL%L1vFT&+wt=MOF~`oNYpB(ABwXg$gPPEuvm%GFK#UpeJ^;5vHMbd3%YhO*Ioc zcrqn|+e1HGpsu^eY3eBn1QnS3`^Mbgb z=Z)Jp7lN<|V$Bc!U==T1=^%TTs8yn2w)z~bUArUPi5J*4R~LBEwfF_$n)`HUwI2Wl z9W5G|UZf}!L8FA3rzYYSNvdO&A8$8U0le)=p4IU@eG-$BMh>AY=l6H9Ay@%koyXy@ zgqL*@uK~B$SK-=1;TvMj`TXpMj?wbTKk9))Ztvk|)9U!Lnk?I3fs{J*Z-Ux8;EwbL zk5_a0Ckp%9(ZSWTN5Vt+6hH)#Dx-s%~)4`K&DR z!4C(NTH#9_`l@8>hvn4U6^5!gV(%yn_P$Km^oA(5ak|DgrCu45mXUKABGEiFs$)aX zS_ne&DAXIr?r=(PCEe<~Oa+g;D<}FRUF+M}Hg&&dNK+Ms_R4_VOFbf2QvGvhH~%v3 zu{L581=CfX3;OJg)%IoEkhA^nR@*Q&_Tx89!USB}L_?ioJ=|GJ1fTudi+$NY;(}V& zT@0jQ;mP?y5a@ST`u?~60SAI7P*;ly(XA3o20N@}#9lpbR2^e6J$MxCNmG=T^>;=)(sJ_*a!s4<3 zULnWWQSF`4u~0Y`p6S(0iHN7GNkn6C;DzNtque)Y4@aO7qF&d+UK|+v%)= zY>TcKqakMOD{PHyPO{g%<2jMQfGswn+eNmwf#E+#v&{Ekfu^nK`^|Pv?M9EGylTgFxH3Xlz-BY5=Sg^-I9v9$hReDrX$h~?(1$F>OjBT0 zhc&;B&Mhih-db1&yC#cdkK9__+i*#so*oi1EAyumnocJ>_b9?YQn}89#E+)Y8;`B; z&+f}C%N8oDM==NN&+!RY(3Kx{gum2Z5{E~Ix(UMu6DWw;E(%yyrrZX|vMIn#{%)>Z z?nZ^cbR-;xbL9#`-IN`VKq#WovX2x4GxBJ(9K@%G)(olM9;ThYm)_r^0mHL+y>E?3 z?w)T^zOF#(CRG09QVF}Dt)7{wF~3#-&;w=e$t`A>@qhzbvcYLtxm2Hp=G%yBl&Pi% z00F4`>^wCxS%#o!dFGkbJ% zvsaCpc@ET?&3`uaVs~ftYLAP7)OHX}XvKUye53LCX2dxTEhaP$_`tO7!9L?EoJ7*N zkC$*-`zoSyv{NkGaN;{@4tO5M=+_q+5i5B=@#n&T%w#zegOn}t6ys_C2)Fg#%W+(E z4X42VXrwaC^I@&%K!5g$=5|7uz~(rg0MWk9`JVmWwUVfat9)Ey zK^?x+qwelNbFHBi?6pCvs;(D^%z7#8;eNQ&AlN-w^~!D1d|=38_ax*vpn2b#LrlWx z;CykES|cLno<`BGST#UkVP>nwl`lRl-|O z$odnjQT(c7^tVQOl}CV^DUr;%y<`(J0RamOV$EI0gCdy~ zJ(J98+A>+je~yR#ndkT#+5UwFq2)^x^znOR@|1qWJvt?*dXXU&VzP(GRn$sR>kxbz zG$o{MDv=69Mor_XZIYtnc#F+Jp)pmJ?9rQBSpE#L7~A>k3&Z>ZDmVfaL+EVtN|jmg z7Ct8cW}?zxP;15kH3x^?{7wrGO7!O)=WYrT9r80@gA(KebyITH}7oq z9}ON8#E<(Ta&T!hh$-k%(R8v=+~JEtUMw+UDvmG+wj=7V?eLOH<*xVgsU$r} zagaq*1R%%a2xInxl!EeTzpAh>z?LqgvpZZvy{hI7Wq8=0PQyP5&j>0QKkC~Z&6eA2 zC-6VPm&Ink3tDIAl|WLIvp7FtJSI0_d{$Egp8t+;I-Ug~FOoR?2%$>B1};lE@sYm} z`6S%=f*S=$pm^Aaefl7>mYpAMk!i9=Gp~6eoiG2zVP~=drbjB$++m=8m0QsEk}C6$ zV^E>4wWg@xquw;G7|P_HEFtQZ=vl{xy#x~3$Xkam%r9{WQrX+pR9~-ei3s=7@AA>lT}qDuRLZ>f!7gJ&k+*E)*Nnd@Ta7inYP8CZ1|9_c z>D180Jip#&BYF^IL{j}rk7}&*!E23Q(Jj@`_mk`pI$9ManXM%U9n8dyhe5J0fA`it zRab}258h1m`keWUy~vJw5B4!w!oft-2x7o0lmKq<5bw@bfh_Pcf1zw6>AzTd_TNVH zAQRv+r$#V#IfpO=-Dec{PxRfljfdJw6ra!8nWw=o)-FGxvNO}3B(elG9$v6 z?pYsh-csi>zhI%zp6iuIeX-&i5TmcCt?rE221An<8djMcA!e13?05<4575e+yjLDf zf|vaW-z&@~7cfiAwy{VHFTYC<|2kIFRJuW1ddXzQsMgItrz$a|Yu*Q#LRV5#k84Pk zE&T2IgQfkyN9gpS2Al5g4K?=MmOVC5&-614EqA4Xm-@Nc6!0Im>hEtN>jJh^0}Er) zYd=WE;RGO8#va!fcsaK~N`C+1UCM$CEOxqgGbIvnk-Mk4k zMg#LHED9rW%USzE|I1-$iDS*BTGTZX5tJfTK&Oqo8$0}jqwAh_#6|6hOoI^65X#yD z%)O}HDkhis)Z^|B-H5BsuImuI8z}5?2gAI3KPA!1oUMqjNgAlrI@&Atp(X;JvX854 z@K8D2y3_n)6k^j9_Ht5*{yh{y&Aiq8DV5Q2h5!=$QiXyA$M%=Drq7q zNot(IIVS{(FfGGuXi0q>a8sz&B2CC5bGgrWItMvryMN2E&r1rUZ4u!B3c91ZzO+lZ zfcBGcwaejZeW9RE!&xfv=6$=`yvr^`Sjythgcwu9?y%Bu0*;v5_BTg=O}t|!ze2jVX zXAo|QOH9>LhXkp+Wd&qTwu7iXQ&GmpN|GnoyUo}&Y_4oj>w))>uO)wZk<@rSX}biq z3tPY@37+CsZgbM#cB~oUpb@6lYFJ-oq#@-qpMEd%HN{i@qlVYeh>H&*APt1S4ZW%7 zRZ}S|pir}?(TXgsSZPyYqC>@MY|}r9VyMrBcYExXarLjN~gG!V(t^2i7=BxnT`~u2MIA*PaG8 zKlJgPZSSWoR^djw%|XVCBFSBK>Qb;-UuCgnlaldK-8h^D}^ zy}&9ZHzzK^Uec=`E*vkbfwhH4voOo=pq)rIo>)^*9Q5U^DLozx*|p+Yc`kmzjX0>m zTRXyGhpQh-d`B?hhpEqb1;~}^JKA-1Dbv?AaIcg{>Nc|8gy^_+jiv&%PZ|Zx%)Jkc zh7uZRRr0Lr{(jY7wSQv&17g{qCxrAi;eJ5QyoAKqc{kgW%mB%P|E zYj#cz9i#WuOo?HfPMnE7>FF8zGPkXl#0QUvKa*D%y~@llT%BEDcp&H0LXDSA!pgYl zm;4RN+`fRJ*|^wV^G7lV1@qjuxd{#24iRg2!y003W(Row`sWEgrKlV6D?0estAs_* z6=!6?U`E#=w~ovX?-={^jktQ8$H99N)6kSP?Wxlhx=h^f_{vrLN92wDzQ61<@jIcg zd)Aelg5kX-o&U?%|BnJBdWsJLor$?#{_ofMe|`c_3_#s$4_QR_E&L=AFAvRub2|xGqha2@s7erR+X$=j z|K$)gooID-IN_=B4NNt1Z}H*zV|PP4w?Wlt{BztX5SeJNT6)b5&JkVO2hR-yzWQ#n z-0Fn?7|1PTp!@d$3|K=uL4Pa!RX?n zyD3H_JCMaTB>Tcp?|2-|XVCi3GeO&135Zu~SnQK9>aPYGFm8V;E)aW7Z~ksmC+uJnDw4`+comvghxAy#rS zF3VpnugBM4zMGT-Sa9RXOQ2b|O6;2U0eh~kd%m|Ki^nmAU+jNgDj z(e6niLak_LgUq)ET&-OXevt&V#|AutgCH-Y(suLL90%k;4MaVe@A8EDfmD)6Hto8d z+>wb0wZMD)olIKqodb%XXH=?>1pn(8d=^7yu1f63{_l5f@AvS#JifA92l^MmBcglc z!Lu$ew5;B(mcfN094m*f%@y_(t>oRhN|dTTa(DJ%Fu5B%hfP%n5>?*Xu16gd0iQib z)HxH6Y`3GWjuimbD*!LCJ*<+FmqC(e0n*ONJ}AgeS3fODElAv_;!SacTK<_wyT4$r z0rNNH+8yGY_+)?;3{dzpW}f+jqZ%?0nb{1xy~FO3HhO%z*QUGmA?{lC=#q!k{sgmL z3m)y`g-?FzY<<~Yp-fwsE&Anaka;RPv}=%K)yR@NM0x>o^rc(>8(2jGWp9$CJwSn< zhH3;Je-~5MCjU=BNt}%`Lz>jLEeh4;Xn+Hc%Im$I5#8ck!u|qGOb$M?wi+7JVU{Ef zAc6R37}o)h(D0Mj-B-_yI^>ro^8Rup(_KC?y|P4&)#p>Iyhy>m29-yGj% z)4p2%9LbaOWr*USAmEh(>v-fI$bxBLlPmB2YT&m#q|OOGEY-;~bGp83E($jZozL>f z{P#^#eZ)UhWga(VM+h{Ro59TwCH^_S6ur$ZIzf$){KCkv=meE{c9gFz4LWq5Gj3MY zVl?b2rNH_!lRSzmbrfb)?gKHT><*~1;$l#Ju`%8q(KU82J zS7&7itC2loLONghpLsN`YryLDW;|ZV{%`y?)c-lZjh(z7WPbU0sc#A2(_2Ko%_O!( z&BfobkVXCg<+NCo0L2U2n+N5-vT4iQwd0i!wzF2VpGx<)&r*?My9S?2z?{nF@n!cSK%EhknT z)@BT6fxp^fME$fJt!1m>mC{;&=UeVS=XpV2Bk~9xRC7KyZ?BlrurRx2M$NzzlgMq^p;Wp{Qe3Yh`aQcFrbNe0ye zo#Q74R;*&}^?jxlWN%V+NkrBJ_h0EhPAc>OM}*wO$y*2c$FAn9RfOsj=Y60u2IhDH z`2P!7j?iT!E=~%csvPlY)9S5EZ0IoDz=uB_XU*vd|G||z`9I^zeQDDEmN&GlYH=^M zQnEYdmRt%_8;kzG)8@x&7XOi@mHb-QqH`A%f9!udp zjwv19@gNaR|m3!Fp!Mv7f_3v?U|_m6ur(k&W#{fhZ}$kxvX zC)SgCDLqyr7%9iYPT?VuL+QS`l7d)`#g`IdiyGIGX7KW!(DTO+l??q9v? zaWFxvMtnKtu7~`b*R`S0RI3#F;2CMs-IxKbhM^bdU$gYLVfhG%rx@g+-D*5?tNarL z13$X|!1sU}eQuEv-pPcilI9I)bQyglwEwK^t@cHJsmX}(IgWtIK;zX65jAc26~fwb z{sXLWn-odab%DV^5TVz(JZV5d(%uf+9~oNoKOgeh{qg~_O8*!OWfO6M=BhF$GyQ6! z-PJpI@pcF5`7iih@<`SgpI2OCMU$#a)f5il5 zTiDu3+EX^}1^Tmir+DS8==)1qvv?b^`>4bQL89KW!eY^!PfD-3o;eNy-%C$Gqv8dO=VyxedcReonQUhQ zRmA7-{u&;kxa99D0h`4~DDU!9;@h&~q)-aB0c6sicFrC;dO7o=T=E&1h2H3pTQB6` z30{?3QEgDoC>1GFY*^fQkC9s;-qN}wWc7MCMZGxWxz=6f$=0JE^ojJ-Ee<4sxB^d> z@oofu15p~n^9gKdxU1|3Jf?aBp^y=Z1)6`Kg!1C>vooKDZDpEy*4&&=n#z1F(o{t{ zUXqKa!p%Q1dl$YI(DMlrQbtIP+x;k}S7^Q5AM;S>!h_NXOG067^tnrI$6l|8Cp-w% z8dg8Vh;;W2QK?=ZHWm;o1B@7HZ(6<%)^oRe^hh!_d37@;d*7Gw%~{~Mvb$2xs#%dg z!>EArBsG~5o*XPhF*Z?G>SxKZ_-_@D)v#t#{H zp2H(%ld(%)^nPx9v~W|26(PG{^}VH6I%3I4bheP)&)M7VkM2T zjDOV#pLsZxQmc3uv8ai+_p3jgW?D=*)(Xm=I)AG8luOBgxrozYn?1S7ZCzEyz5gWdm zu5ZoYNZY-ROK{Ax?^HB!yzUo88>}cE)m;kVl45gL zYIoC~4dc4L?6aH}>jy3s3s&tL{ux!-xJ3D^@k60(*IcZ-cN}BA+*6-`$m)v(0n$X? z0s1OWh7LMib6utJrz~%)_3c07dd^!OJO-8GPn?rjXJ=>u-tm6KPQq>r8DgQ$Vs@epr}!w{KKK(cYDL zaeMY5cCi@t#CSWZF46qfhSg~Z;MyVM(z!;j)fIz9bkBT|W`1XVp1}T_Y?wIg-^cNw zUgFWWen}_KU9UY#b$-vViH@frk4#IYoZ7a(rV+osDkUdYJ$faASY|rB;YUsneWTl` zrpoDqoZ037$z}92;R&$BQ5D7Jy`B0B3qJFsiSC-Gg!v~Vk0u@GOAl7^^ z{~?oJeBOq!$&xZMx`m8mAvDz+^L!PV%Dt96g{k74?Ym>ctjZYTuv+}fV}w#TLMD_O~@z+H)Udr3j2?b}TGq z>60qLGa0vfnskGIaGR%Jolq`mCS@55S6nX%4DF%$T0n6Vc0M7@kB@9p+G#Wf4)B5( z`GU2Jc6u+6W*d$e0X^wZ9HVpwjUp`7x-o$4Pu`R^pK$v_V*Ix9(B$&u+a5{hm*xzi zwOoR0hn?5A>rdbl?$GDSBAjt*-}sq#1ojJZw%^m7#aT|6JLaUiqPz0guY0C=Xmg0 zcgm^VoS#Uf@R;#N{Lme0oyrx=Nmma39+!KlC$r{dtibxI+L{*rwVtIcP`Lj&CA`#r zj&FXSB3cjg5k+(HWun8RCvYCT2XWq+%+I~5yzZ`*o|l~;f%5E?qvqBlz#o|78l`Y9 zvQW2yt6L2bk9-*+Cj=d6ugp%7s@ z)Ic3MTGs9+7SoG|R!9M=r#vHPhH$!>>wF;iK&3EDxyVtAn!0#O#s3X*Qe>lX@o_fG zqVd}L*nxxVGsdpPx!w6GCD@a9i_(H3y9ehiygy{8+MYBNwMH3yHc%wwjVDWy9M-dcT3Dk#aP5pxRb0r3i@%4K%T;{iG%vW9$RGltP|)6ojyRHul9`me2LM z#^#P74c^?UN``${drW-CP-b?gMM%i-TZ?K!apehoWLp!&E_L{{4!9tPX_BAbR*sr@ zXj`!7+*7(U$J)PTT({nU`FNAKBRA*79O}6pXUT&lx-Jl8KH2j4VYWhxBQaR&VN7JymUo7G ztwrdG?@n#w8Ja|trtj_}#Z7?KyavA-Ca8J6TX*TRjd1ndgE#~WQHDA4N9sHijc+#uicg0+B zwI=e57A#2)^1{Hf8{xG zh@(lV0YUT;TU51_uuydWCdljd1jZsuvQr?P_!Oyv7sE^A@$}^3JS+PS^9Q0UO+s*! zF(R^W5ONLOX&EdFLzFuK1@?h#Ose*C=kCNtS}JI*y-B@&A9y%q_LO0L=o&{ktB;Z^ zrXjWydnNb$wNBac%|8a!J}ylJjT~+Yn8_AZsyv6lFFVK7kso{(kv%?E8;PCLYZ}0- z!Ct_I2F%ZmvN$EbS9vpAf~t4Ar7RRqhKY!#G{9+ACVA}H*SOcZg?Yr#DK*8h?HCH? zsU!*Bn{f?G1oC|Gl~W@`DBNkDgEQBxwZdIwobd^iF)egtciIY|0_`k76n<%_>0bX( z?dn79d`ipeG+E{hJcy39lxW$X9{wT@oui3d#Xz`w@M( z3+{?z;2mBW$94PLUVY{lrRQknP96zA@!W@mRVU9B1<1y|UG@93;Z_++ay4PuwYAPG z?bRsA;Rv27*c4!PJnAf3Hl|1G+yBI&pr?e)_Gi{;KvN4T{l5P&!;Q~Jj%F^VO^*gK z*?wjE;D~xR9oO#9fYu)xsDT*B#mvBoHT_reWibJisM_J;IK+;b#q0^d(y%Gp`fDFM z9?mz(776-V{fFRv7W~Jz5jx%;6=Pmz10t8+1tQanhte4;>AKm70Fyk@4AU}^k(QFp zOCIr}=elw&rPq$Jmkh5m6z1+O5ckK?i>aI8h|bs*bfs1cX|w2|CNX)pc?7>LMN1o3 zY?Y>VOJTw~u5FExVXC=>LhX_K-DS4tUC&I3#D|~(x%4iCL@oDI|G_#Xn|D3)04yNj zx-dzqVM)0~6wjj8)Ld}sTB2DJ?t;i4$Z64eNH9BA*(p1nVh|)(BlOUu?AcgRet=2& z2jdjQ7m+INGHsNBeZ5oLn|kcZDdgeNwi9kexTXzaVd*oxq~c>YCiny(f-M=Mi>G)` zI?*#}o;G$bUIM{DHUV296J=PwfznO;$vBi?8)^22+l)wau=pbm&Ow0$J<K{i11f4X#*NFV59|n}zEP{YD$VIA9fE zHxttY{OUei1nN$mt73U${ea&J%8tA6u!zI1FO~IXfuQiNoBb#{RO32ue zozrT+Z&tN&o9?xepAD&PM9vnwek0*dCNOL^eOnoQyvO0^mpO3a{$qdG#txwCSjkbC zUI>3)=BaX^Y26iQxN+J^jaae4${esgJ3u81`@h00{l{V``UetqFh4Nq*Zk4m>ku9N z!En0$6+OG6Es>w+iWH-XGU-1%B3UMbanAUo0wWMl4un`oSxd zGZ?st-_mmI{Q>4Gs$v-sdTn{B6_*lkgkLieRz!jxFn;uCJ zyU$oYevl{^3+7_=C0GO@MWfuHAq(l@mYGf{xV|rGY!#&JDNq#3@0CS7#31r3NNKB! zR?TPBtxuBJ$@UqNc>#0c@^f^AUu4$n>H7iJ=27E{T-Sf4cHC)LG`fi{vA-6qznAAw z^ni+I^(Ct8FvYP&TgD*E5y#bbJ>}}0sVQe~RbT3PZpZNK;A>BZ5gLH&q&y0h`~1Pc ztnXU+Qz|HOM$ckImWayzpDb4o?Qg)OA`10R@vkN9*@xdJzgIfo_xN8N*L&;otiu4~ z+DZD^Z91!R9lr`&%s~|`!MZwzR!TFWsa)p4?6S5fyi3_ zICk??{I+*2wEFsziSg3g^$dxij`+}~IU`ZWKlQs#pp}L?40i+O<3;otMUvx!l?z{`P`;Q%KC{Q^quL81 zHlAm|;#LTsxMRtty~VUfLOxdI6pmpk8Z z*1_U5L|)*+*ZCbdKP0rh5+D_EZrns8eMxDtO5^t0Bf$*qk5!-Th{=COuaYJ^|KK7X zmgmb|ia7$3TjKE|qQGyJ&i(~?HS7DD(O#>U!^3}owC7Y9oNcTFL6uWMk^W9i)NC19 zw77GhhpSG2%^O1`gXZ}@+BOu_kf%_)sob(<+j+7BdMasTB1o;W$ks*~*|@UUmgN%$ zv2^VaqQ?=Cl%@u(hN5~#K(Sou)7KB4j?rdRr+zaZRO-r8FkfoD62bqh_$KGl_ z-sHn75lMDYAr9-QXjT99#jDFJJ+nk0G3#|JB?k ztFhpPa9K0WWJ_5yDkHV0@#Fk8*{#+V_iqP5`z%#j+{k|74cAB|YvkbmJajeoA!n6> zUpnd5rQ2O~_W0B^rR6@Fe*6%!q;g&K;-65o!1ORRm(l}arRV`lD-0U6BTMs5K0diB zyVp3xwb!8L9TA+Z9?&GEbfuQk%1hz;LKuh|wmEE?p1D}$Qd;Gs|3lv;|EZ9LVVdWr zpVNNk1NB-Iu;Qaj>E6Gs{|*(GgII-^U;0~ z-piG$<*x;m1t&1|ZugyVjLZs5c5Nq?vVuj?e8cblXQMr@;%G>wBIhI;^ivsK`@h(G z�)jENaw1Mg%EIl0iVB$RIf>ie$+-XUQO;h>}4i=O9tCLJ=gV0t6&ykQ@XgXNt_* z+^=tUd;503_v4N6{=6~j4yEK)owLt5Yp=EDTyqAx5sMH8fw^Va{7A8vlk1jan%1f< zKiQ$j;>)Wij3LHWZVefZU`U=kcB0pa|rt0rO&eVW2Z2!w#;0|3j%u&7faaeTFd=yut)2hGh=-Z;iE9xqH$xaqpSlx%zOm0!0$^f zCwbQv)}{4=qP;FX0+%N@#X;&+%!+oPltEm&07mWJ+Y)>a&w!7oK_Zm+o$6Yqid(Q! z=}RbKLEJr6hQOx6=O~CkJ|!##O1PM0LtRA4=a>IrJ8v=daw#gjta-p zJN}9efO-CC*YI!31JcXBHc}cwSLgdJ?m#^FlV5)20rFbaQ-TA>OA3>8u}Q|nIBCNY zF!!2HRpmG(W!MAN(;R2QG3`6ooTpO#7}{-QeyY?4k$v^gT6&O?$t8r6q-!;Qli(0mrv**BI}& zfbGwJ-i`k$`%4VO_W{4CDmHk?==b^Ae|9Rb8BM0_fL~;0KQFNUZ=e6yPt%{mV>95h zp<6ikAG9YQjq3q=4ejIJnt!`8zkM0_ftUv+ClpRr`GNoM)RX@uZ2bR}_XLj1^4$c< zpIHCDKHy(Rx)=_QYnPQaxBq|ethyh7iT&QBOy?K>i?Vf03zP)TyE-2KrxMP;zOU?> zfKZl`_fg@WK*e7KJHhY%e?SrY|Cb8m|Lwbqy7QN>1nZsn%hNqfYM#rWK7SKJw{Iww z2CSD;XO81@?P+(VFN@;?Z(rG88H{xA&wBwXT_CV_WI0c}+V^e-#8-j76_*sw<9N`N zvjSpH1|f8D7=Q~i&C4)i@z(*of80iGWIiR-P?yUeMf1r>3Z9!qSBEKA1iD{$3Y!td z0&JhpeZ5ocZ0T7G2Hn<@nbM$bNTgKFdPpRuIj&r{pk?*aB>p>hKd5~0KH3imq5T8w4OZTtHN zIRWU>3p6_f5maEOxsT*vwn|(btGlkmS_ZaX9k`A=RQI%06kiUG`_%rBO%5ufy=8M$-Nn^5Ki7tLyU+Y4>*bi;AgO#_w+-t- zv&U|6=!c1IUO+F|8$~ND@^Y&Oh5T2hAeNf-gCuy$2SakzXwM3l#Je9`XH;xSudL6@ z`>H*EAFjEM#(zXhPM_;$jhV2k>iGF`U(jK^2J1%sLMnvqw6|CeJ6Fi{Mb#RQ2$0+1 z@jkAkQ^iF;Uj)0gN8N=>Wss1~ER!~JlC*iq8^&*L-R<(?N}$2?43pn`uQk+QY|;g{ zQV?dDbX2dc{mik&`?wE|;7CiFlP3bKvmv92u!fcKom9G6@+aOSrdWd_!si<;^CI5o ziSR*e)eoyPtQ*c}6!S^##hbHwrWq#93RiDjulPj_$a~g}yyQF&QxTZT$I_ z?4C%+{MAL{6%k9#uS_@)CVv>U2ZpS1az8q2YS!9a8&Lygk(q~kdqC6UZanY|uLAyK zE#P?})IG=~3IM{;Ty;S62Mh4>hWvkB!#Q>x)IlguMyr7vSPK@@XFOF6lh~awmpaDBr&K4z+M&?cy6kxn`Z<>U74lA=z)j?!DF0jIa3D)oQTgdX1d__ z&MaKPfN=EewQl+p@N_nad`>8N+7FxaK|i{%2h-w}{-Ev4nF6HF=K*00>uQhn3jcDw z@sbG&)Y>8E+&X`-T7ig*i7SxEZ@D(jB?NLVl43wCqe?WX0`N0;8n2L7a!ABsjFOxr zjGp;A18P}LzVhDqh@Ns^W%L^>-#e<{V5|hZZ#QUI9-)aof2I6JjYx;qm*(?3zPE4l zuuFq)ia)>qE!fAl=h3^6M|>+#l1Q?k)0t|wuC=7K#H|c;w?IeanDR&=(bZwWw6NoB z?Pj(?OCbBw?uQp2h%;oot}a}F8o$d=pl1{t%cRx`3KiBW+X~peDGZ>CKLIIR`7&E7 zcJL?+kfLBQ#j zGq+uoi4I)f=i18A0f9>N68Kvi&o%h~E%mgH!EEVljWW~0d?f}?ia3#h22C#t$+svk z|Kl~7EUJkew?kZKXRMU?6&80#cu|LMJ>pcjhluDXI(PY~f4wnQKne9la3q0_@uprc zdG;-O8$-Sm5|Lr0-QD1Y*lf8ULng74ln`Izlgyxw4#&%PN1@r%cvJ@Fg);LT93GoU z&7*fMtntFRg1JcFD`Pr!mdT^S;j>jM1Vzfw1392vEsgqKDpx~CJ3Yf^aLK>@=V(D? z$8Amu!r*uC=UPOP)ig`SuUi^h)Ai@yOXy@iHK}}{Q%*5exPa12HyQW3B7E&Gp&k1= zdu47N9A2!e%A_GHMZ`$wSlK;P;v}3AU0yWNSxWzAV=()D-N|zDtpU6R{MOvPrLOgR z1XMUrV}3-@Ndp%rmPlr;3Ul#opz$N7`dK~0kkbDphL>qHy{sYv0=st9%~vUm>rNHY z0#s@ui>a!TgY8+pvKN?fc>NJ!4WdD?mXUIJiHvv zS3+H7`;ZOWUuOK7K~au-lc1TdXaJWJ!yix^5_Lz5_4N9~FkSH^nAD1_G$8y>@A!)% zcUo|z!9_Rfv>Jzted~~lWz7GjnfHoXYyucawQ21?VAAyJTlgrUo?$jz!q3k z_OfY|yLWT%g~K0kGY(aKrVMV-E!GwCNqAQR)Wu7Tzej1>_N5A;F0kH#4xk68 zD?ITywzC*n3x}aK;1xEWt}!inf(P+9llxc)c-HQL#9Ap00Vp)A#GK-a-C6XqNiQ3{ zF3#!kHw*RNGCUN$^`Ea**(T-;8Ekjs7ZTgS87lQ*oRs^fwn>|^Gi*OBpPX{YTJkLQ zCJ5iv+po`2yEs+1{dPp)W;>RuqdTM!|N2y*Yi57nyJSyVR$xEq)GO)ZM#s28?o69b za-C5_ei5uu^YCk0gTt9r@hLo->*DOI$my!{ptFNOJ&(imBk6a1mzL+DZjIZ%L`H)= zn-d!uSLTlETVL3bb~gzbyw#YLYUsE~e#q=o&6*f#y1uV~4r&Rl91R|XaSCXuZZ9r9 zJ3mc%wVsH zwZ`2kU@K^>@T?IqjallieYRf#aCw>IN^imf(9C}~t&c>T_NdS!h*Hw0cZE?g4_m7W9F+faemrAElLAM++R~6vfQ3i zRrX232F)mqo@p5uAg?l#BWU1>z5dsRy>q(qPYnWN$5vpUL_1kX-L``dTIS3u6`Ob z-?YQ;v^n!NBZ@S}%U-3yq&?MQ-Ocy1Hn8#>0eJ~ochFBi_uvh|hfWXb^{fkS8ScH% zNzh*v+!4fx#H&ntVqM^gv79F0QZ(b2P+>V%G{>x$!i5-Qb{wk%jKUL*Ak?mmXF)HP z1JvI&@NTyyRN&X!Nw0ksR8OcjSzsK^z#Uav!7Mn5Koje~Lz5ly77wLI2JWAZT{6-Q zYj(r?*yFoY>%943--B6x_?}T1gF3&w)F#s@!4pW*NA$cIEUY*nNM#{&1f&~P*6q9I zxP@{(L-S*Z{`1iS?^ryi+C-5K_T7o_Z$gjUyj;aKxutq`R^!$ucz-@S7`I4ad2qlR zwvn+@KeRRWW~yan8MCqgPV~8Ia)aSe_ti%EnO@O@0%T?#R~ZDVAklJ<==BLT(`Bwo zGwE>M6SZx1qn=i>fj)7Ru2oXA))+rC#?Beud0Yf;YE~6m89e(b{7sj4%gCv&9UiLz zeM~jo2sX312rG+Vj_bOVFhQeZ)T`5PK&28J(Fa=&SfhFxjF6N(6fHj)IDsh z4(H0iv3^#C;}sDoFW1e?H&!ZkZ=h{1PXA0LGkjDIZk?i4qqVlRQn|ur+D$CNJQFe* zK2&_$N$ipTFAVun*FcY56zP5b&CxGfISV^g;u`zq+z5Q#5(9AYJ}x^+w_IrPtrqGf z{C#|~kf5?g!dqt|$K{Iw;%kI94UZ;(1Wezv*Pb(ZvCAg@Vz4U;|+#nBkRWF1=m_o_<;FNt2saF(< z^}MU=)Be@?em{rt*P!gB6RVMx1wjhbn;u?PY}zwtPVgz7i<{M-2ebDU@;#wi-Mbyd zg>>aXOI7oQtpVUc2dc%^W+-zBd>3E}u zA`VR5T>S*e&TgTTZyZ_&=GI~GTb6P6e&&-AQGqy;o3FuO1{Y3_k-NI#wlsrkC-Asu zmXj&}94Rr`g722$CcZ^48%tZa-jI(M{f~<@ea;DCE z(NM%y1m%txfj>N^>z>JzdexW=EG~SJJ{J-|n&NiB$3DH+|3YCWw#~bL?D$k!hSG|p z5;i)Y!(4VZF8uNRDmGl{4Fd~`;GJQ=Al-iWF!Ad6Z4Prv@AHzJ#Z;JjQaj!0z4DoQ zcT3$5-?}>&bqjhz9406PNp;{4go1*M`w3ZfKd=6Bq%oz4b6oD0d{~=?t{eO7cHE>N z!BN)-j;Z%61{Ts6e!5wzLD(^$4r?%0lZ+|i)WayA5M5~R8*V7Xnd@bBa)ka(g7}h3 z2;W^u7LltyNo$_^Qt>@zcykNs-?xKd_-Eg|nhh!$Yy2EkDGR4^OEni9V){UlOcuAJtjKAbh z@ayVvRu%}lPE|Hys*XW?A;V(X$)Le71iOZiGp@UBAdV3h+ILB1xORnAB67XBF|cqy z@!Cx^af|vUbOAFifwU?dca7)SE85_Mmy{gF!SoEY>dWQD<7W4pEor(I@3msUAh1+C zQ=R+nIB3R3KO_HkW%+Jd)IOX_Q4rC-jGPkM)U7|C-`M^+uGro|VH>W+;+1s{-(tvD zEltvPY!&(B5&6vcG>2qwelL6}We?})h$gFLq87t6z1|lJ#(1((nfTavCPg{8m0SN{ zrIW?+q!ZeA*izp>oqW$K3oDD8q!a-o-IZ|8#~2oE%^8iOqV91nrOA_lui;CJVr6vm zI7}(5DpF+Gm2l;Hx79U-RgHiBvPXX$2zx$}FWCNps-nzKKGhShBH&U~MdG9}w^*L3u#*zB##{rn^y z&$5uIvL5vsis|AT!$Rqd&}&56y8TRw$H>! zpe`)Rc@c5;XNFQB89uCg{+>{=%v9F?R;o-Amn0Su3zW5P$9D#t1j}C4^>|xSph^32 z45Nw^T${Wrri6^VYtTTwMkhyx#Quz4YOyWUDZdi(VhQ-M^e^?wHQ^Kazu3?GfUTJ& z-3G)E(d>0o6zg2=?cHV8JkR%mZuF{a$;QOM^`-0+!YZ3hg2!L(X<5~Dj*qpb_JEC;!+wA!@I}usZV#%5RrLlan4&&Y&eUMO&qE{v}uHFp@_Lb)5uHi2z2uIY-GaLug0m?oMn)etmsLIS{ou6N96~J?*=wdjoz9X(OSuf(-X!+PiQ4 z{6NMx7%*;X6*nOdLr{;Sh&wok{L`iw1`x)WEU% zi(7~$3E8{_uX%sE-RP$x9;@*=bIjmG)I3?=>&ZjU)8NJj#dIRxjMJ{1fP~oPVl_am=Lj%6eLI~t5 zj$N~0u$k*tg2XS&2?_ZpR^ zpXrT6sc^lLP5E52`Q`46{`Qb-54l86#KP($y;WQ39>q(3p|Xky9Rg%Sk5{)4{=7M?39cw8>P*fA0;NZi>_TsEYhxUh~dV z?MAQqBW}h=vdW3dIT_ZjMVZ#FD)gPag~C=-RSL^}X{_1O@o}B8OoeL3swa@@6%;Fb z->j-fyNX{lxxa5|JXB=ZdpM-Vp!oU*t?RZaPw|||`zBG>%O8gXsm&eXqLTS@X}`u3 z!~bTf_8>ljtm@0TL6M|JiRA{RST*XJVJ35?Hn#HB9viVqPqODx9xGLSn3now?rXv; z<@z*Wh!+x9owgn4i%$DWfK@=}=mI>Oua#|9mg3uJ^~e6RJ97OFl`SM)Kd~}RucH3y z&63%mvy}T|Rd~WMvwI+!PC-)lw4nTpV#+KN0ab5to8nRWNw;Q_y+Zwv3#t-U<9fHl zYe%y|1EX+hSC*$8Zz9{AD0|p&b))|-M*+pur@$MiUBh-VlbWO3nyeQ@xDmM8JDCKN zYUUzLgoSxNAuPqi+7DFB6S5kfRh->38F*!4Ub_gF6^v z#t*p6scg2Ts)0nRV(CME^7bC#$iMww(HcB(jx6$qln1v5Mk-CM90&ULFH=*_Zp3eu zsF#~7Y(1}H)i1;On}`Bp%yIM$RB1WXzyHVU801qV`ZryIKZ_egl;eN2 zr~Y+GsH`zw!DW&q5Mh5)a{hTz;5YQ|e$Wt671lZopei^bFR;Ti~E)NIeQBWDs=cSlFWbwbRjoJR!&*7S{2mFdEW*`JPn z)}RHVKq2=ZD?U^i*>VyBJv*hN>sAk!?Tkn9x)EwVbwnqUiCYMNS5V&T;!rJ-+cIu$ zI$t?ID#dLrUoldQK~(>H6y4snXazeTDVKQ! zT_0=Xx#Du~M<(!S#-1Lox5q4@{$7|jUD8D`pmu@&8O_iW*?7=0ivx{4&Om*?w7z)I zWc$9+Hk7TLF)ZHVWp5w?du@Ze>hYApLg%ZBjC+V~_k^JIvUMWsVdqFRsA$ZzK2Pwp ze+LziptqE5_1+HQkL6iClD05%CSb%VvILx)$t1`~8 z)~SIRtYE7jrO%I!gg&wv_)fVlhH9$W&2hgTjsSCpG}6?J2_k|;z>iakUM}UA*<+Q0 zm>5<)-CiN2_H{e@)0@@7%X&|z>qaUJutW~S8Ni-2%h0ntI@Rn#)!L%@^|j=W(zC5_ z>tl*5Ae2DRa(9;Vi&kZrB)0Bn&972mWbwh~_Dt`Xe!U>W@7wXqn>SYwQ7aqGkwoqi zcfPEJo?5@jX-K;mg1Oo5Z}lW@EpcUl-qqJ$HNyI&A;vl&7xBr-qy9A6e~tKjJ!l40 z^~j2inW$Hn7m2IDlJOuVeL)92`!hv4wGP=#a>OG~_?=|j@lA71aF>(jD6AK!R?EQ zmC z=wd8g8XTy%-#bx(9Wvy#js( z0hj81){#t=?TAw$)=Kegs!8QKJvv^ zeUVw&Z8Py*s)OyHbAYmIpdm|l<>p52%1Sgi{xfO#9bu-*VXYNO8eh83d0c^GTHMRv z=d^#h32<+rf6}jRpNzhLaWQX@sEmHqow8BoFxYnaXdlS@!uLJzl}ZQH9)(hPO#7E3J$@5v?1y42buG%A{Q@v|fnZ#$(Ri~sM-&*z@eijOEeCnW^Cv~yj6SkAC)RM267O*~Eokk9NJ3q6}0 z_8wt}7w!hrYqk?HHGb$!CA45M|KO%-_``I3k}>ga&Baa~K#AyvRz}o};!hd@gq6fl z#|4?ueYAZP|K93}0AeqINH^GGa#MpyBb?6gbCyK-k=x-~c9;JA*FZYtuNKg@XV%JD z1b9?dCbkz`;s;1(>Os!mi}bDC>tw12(kU$TOr4qJl_I%8OHnqBq6A_kf<%jKkxgw} zHd9pzd(J*|8F}rSIJuIbrTX4r2WXS1kIG08X-n=Ke!m20jj@(8w@KHmf0SmM96A_L zWICLsB0Mm>`gLOr**xQu%ygpR;~oa_m(Fbb39*73vm`8!+AL==m!%Cps9J z6%hC{d&EIK8XoNkCP7}kT^%Q&43LjElOsz?4rzd}v9gP>_lX<>GoEQgZJ1eNUXV!+ zR>EH(1^6uH&+q91M4_)4IiK{z;I21p`;MP8n=$G+QjH#DvFn>+-ZySfC1)3NsW7#Q z#eVT562MAWYXYn35R=6%*#|r50cKoD3!QOsMu940HF%=!cTReeD4a_U1ipsrHXzsa zSIc&u3+Yu@Cmz{P!LqUyOQhnaMKtF!K;`=q09#!3QXyI8B2^gZ52fB{Ybrdr@C%;s zL&qgVc`f#EEM)@h-ZWc5<$7ddVtBABP~9$wi;0jU1c8A7_X*fcKRItsc-24>KAH9; zDdx(N+lxe8yb%y9-wnVflB!D=kdwi$OiMMDNT)y=X-;vtF{Q4WUo?e+8(DH7^Er1D z?&$^a^L`J(<&3pA46CBNday}&Q?R+hpaso-A>atINeL3jJuo$IUIAE;k|`ZID_ar` zR6FRtxo-m?e5gKhaV$CoH(%AfS*78bvh(A;_k5zlnhEq{8kVsugY*gKwonxERlg*~ z-IQP`H#eRE0s)d>e7VGqz5WG?Gm7Xnc)V0t+%RYsAk3Tb^vuYK#&LV5{#!_{@7&{H z!3NJWXA;mx8C^WWjs@qq3d>w{aHoH#^?)(hgYpiR{~WU%-e}EEI7E&MFAQS$Erc9J&bBa zpU*c>ciSn67-#^Hrt+pCU4AG>R>_7p4yrL&+D5imucxY~+>hT)TSpo^egP5{$&9A~ zhHI_ob_-wjM8&u3*~QT$V(b{?*6O}Fwz*@^fMt`IDp(A~M%~f=nDE8%3SjMr>%<@> z<1JBHnF40r`K#6JxC-pYRHBh2ZNYp#+m9Hyv`Q&HRy_tbfO)A#EVRUt_0f5>9kU_x zmmbgjtx#S!Bk%g!8BiDs(+gA@@!5b*g8gY@ zu^jI_ioI`%uvRxoWqa{`R$Xn7lVta;wL;{FkvC0tJ%img&mcFWcZ48Z9%lMp;ytta z!l{3$KR&VhT(BfAr{Dg*VF256`8q6sFXmQ6>g`wQG3kJN6E^1*QtlnvIIw+FkSsEg zW9W$-a;QbRx#Zw9Nv~+6jz_NQ`FdG5;elC85e~~3#dfL%66PXb-!8BiFTTq7xOLvLGNDS>Q0m1Xo6<#l zHbbf8g7wX&$Ql67G%V@0SYlbv-wx+k_k(To*{kpKv&-!_4Ke<53Rwv%eaXX$5N}5< z*0Lnk&6MjtEG|)Fs-SQ3+=m7r>56p3E&D>UCsWs#d0c0`sr!@6&ba%M-qqxmdt zPT_&c(T9!1=Sz}YJ($&(;~z-lQq2gam*)yTA0a78G2K&Gqmd(g4FYqXA5JXX6Zj2= z(~4iZEEMRWHW0DtBHPhKaQg1+#=LA7KrORha7Wv|H^V;FUe-(&z`$1Im)iYE0$2J~ z`ft^w=nQ?tcD#SG{tvs>fSKM8jb3$)l~!;pcl9=F)69hqrxN$9095JVM0zWVG3nP(ZIjYt^7KjWN5FrQ8>0F{6EM5ykL>&6 zBD?_|qv`;kJRW>(oBpG4cK%|4`oJAuODJ`q!3j@M3k^@45$!a%ryJ72|8Hvt>C%dH z0e!rru}dG`(1Xvn9-*dDC(!RTJlyk2%rllg9bkZtp?Y`YV0=-ClS1InlIx>J5=+lm z7xCj7O*2wWdC@F#An^Nsz---x+zxhT`BoCiluSTLJ0keOVy^GKt8aFXZTECKAFkm? zqAJ_KrI7@ti!)^9Cun#`_ZKKrup?(J-TZN?n8+?W`)t93CsqkLMqvmUI2SdM7DGCj zE5fSV;AXOK_QJf#pEdU%<#18;MGMw{XA4=DVz~zoyNiMg`zM$S4@drm) z{um)bOf7_jP(7{lnq^P7E$o&`ygogh zL!??AM`CU>2jlKEVLqTar13rua%1b8Ny#nL$Be{Z417ya;p$6Qw@39;RNS{xCngc^ zZ4EUVipY_+m8}fqXsWbZMkNEM+$69b5*f(feY?AEpX$zY4Gv$rqwn3F-Il}R2z}kj zKFBRB=zx8qzJ;I+nQtZC9bIeU?F4qCy2JIcb(pI5bg3J&neUR0%XIb_!dqsJn|gGM zj*(Hr*wsBQK}6s8;!zef64}LEHc~Q=i*9ODh$8FfO5CUTSUqs^Efr?5`3KH-M%Pzn zP<f5Q!*!DxlJaB-?M=$_{5f3Xoh{DnxNRD?qCBz zlWT3>=*@xK5O)^5)?HwZK7t~7M*B8oX*?Nn!p`dZ0>SapZ{_!^!Grlz5>fi&SC?|k zGk79g%+7zON@y`WJCR;JaG&}H&fYZJylFkRM-S4?b7|b$zs#*3NY=R*Lr-Z%v3)nv zp|`gDd+JC^9txUQFBy;=HE|(07#6XPcvMz)j+$|$&UxFaCn@`hsx~Bex6tc>Vd^}E zf4BaPK;=Ws!-q`j6S%8Wy7)FT?qYq9NqGbjAF{LOgO?C5gA(rd$-MDXzb(eHW(25R z8_z@D9(DU}syD)i$xM9-#Qh#gzkvIj*{BAt_>_bbv(qR&aZQ>}Es=Sn4Y&ZV0VD!i zM>f86g3#%P)CsgIarWm)Fx@15k|m9a22b}d4967do5tdFbv)_~HoC#Y0>}RKPoiOs zGE>jQZGzL5WnVj@dfrJEx>AN>;*Nz{p2^+ZPp9K&A%&nw!N0Eww4rn<_qOP#Z3=?x z(uY5@s<6*g^>C_HHn~#OrOt@Mkx7?aVf6=QoU59(O<>ovgjOLBycl%fY?u}eD@xa# zBM)K_MYb^9H#>6fcf4kg#Ygb5It|Sel$JhKuhfup_F3gIcW2sE{gb(aAa1?J0B`8m zGl!8^^)Je|)0t;#TFdxl;r_(IM^~J=5^RNLsqs}rgiy-F0fjD)^7HVee0Ee?7JME2 z)Q|d!-BmO-C1a9!Fe?#`!aEc`KtSrN+sk?MJWPJ)S(NZc;S616mF?i+53wB=U@<>x z;jKiK*7EvbJ|vb5V3Mn66i@vUF-?O}$oi7+!g?Gzb+5h%lR*fMKHoX|;oo$F8i6|0 z?})){P|VPk2I7u1V&F-t);JzF8B)dyWTW3P;>;nwSQD5mUvZJBV|@3Z_qZQ8CI5P$ zV#|xOe`7lgQ=R^yR)g^jE5vNRB!qu}NQ=?-Fd$sj+Xgdkobvuf6NC9E%V}b4qCTJP zOx@?w)p~K%F5_hb&~$M9)<@)J!vIgi-T=u*<@0Bv$?2h>xi`{ZR zH(%0rZ^wyoN8Se#ZPfPq$90tP=tkU3a>49 zNoY>8zQvhd=3SIc3&G5gnRdm)oGg~m&+cn&7D-_o^4(sYq*XsJn3hE9!qO==&z zxb5_M*m!N|dO3>-;7Sk2Pgl*6B;5_9EX70F_2Z7DoEkNogy1Z}Z4GEleV06u-`>qE zJE7Q$L9Mx{@w;3Vyq&>D^L_(zzu(vMsZieR9;#6DtF{UMowuH+5tL7t*ibSrgS6N8%x5pjGdlKa^JEOaQFZgs4*@ z;_&T7=@D$*z5A56&Eu_Ia4AqRjO&=fTJGC|Y3K?PC9__f9_~}s7_y)sKZ~=mbnTz- z_pK+${CY8~R;>GFWb=zYX2#gE{xDgY@czr+oA(i3D0`puF+bqZQPU?Ko3|q}Jn3ZN zTzx=v1FLA`Q-d9f*cmj_}i}GeX>NKLqb#d() zG(205sx(|1*CVP>(^tJ0nRSX*(&cp?=p7@mB#{IonwM}GhpJ<*wT7Ev_y?I9p53#P&gp|sgL*XW2M@WVzU7*URxALq`b?R3+p~$- zpaMyIi#7lUMjazg(t30FN1 z>vjXtaW%@s+f8nL3|U@YLW?9dy=mh+iPnToxbQBtJ&c_H%}#gAP#gKzy2&H>9k*_c z#z<3|^pW?Llgap#sG_bs8IyZ+!4)6GoHyt7!PAqaXqA-2kN~d3xDUT3(%uFemM(q_uvgl4N<=-NR z>rFZTF|a7z!~X5@N?bsjK{}9LA#4T&~D2cFx|p9GTkwKQEy7` z5LlVkbXhwOgPbo0#IF3lH@>9u#Jn#$_Aq>+NT~LjpRmQL6UORUH_W0W{q8;#pEKzn z?U=5E!0794iemNgykeecMuH&X{Tr7goQj{OtEAOc0?90~jbln-d{BH7ED*tIV z$8@;VPAg<3*2s7>LT<%2%> z)58-~CE!i?7Q0Qk#PIoJy#|jQO&xKY6Mzr4UObBDcUm*9Nz?J&$GX3gk$Xt#Rprir zuOFxL@$9StV(%pL{N4S?*CPd+@$7uN$|-YDbV?7na*?*iJ0jLp4yY>+8v_$Shg1rb zLq3mfZajs^s6%d>2$i^KYIo^3T_BlpB#{>t{L&WeDd;Mtd1&?4w0-SutLDNm+Q z^-F8PB6{mF z9e@h6d54Ni<<-3Ct#ixc4N>1qPM4Z>3}hGN2d(@%G%7D6FBGAvRI`lsB9}J^pNdkg z1|!=`0B2QXr38JjD$n~PoCBMf41h-_ZD9HN-8Fi=03qgc_*CUdmwnwsgX@ctfcnUd zriN~4A=9^=wL{>yBpkFJ?QYxyeeETcMs4Oo=g)Czq#oWkghm?!-!1L@0n5gDKV%UN zpK0PaaO~uX=wjlIe?jozGL|nb)gaLdFicQWW#FL8B$xy6kfZPO#M4L0FYCLh;7uaa_?Jba6k7tp;B(6(+g!(v3)! z{{f-?1AsPW{_A@DTQ~MG6}U#Icp86!82?0JuRmS%^)+0JBQg3v5MOXO77XfuF0W?V zn?k}@{v!0jcfe{VfwAg9a^*fUf<=rD#37XeaNgk8c?s@(RY3b8 zLkipew{sy=M;VlZd;H1>G6rC+V!k5XW5rJ|yN7teRO&SepWR~BYxiidbTu()RNFWDh{=rUfpmgV{+>%=@VfVy0wV|JsoLb4AdhKIH_^v%_@;02lY| z<1UL5K^KLZz$nVIQ2;34hc4bTOtgFYh_#>XYCk_?mDL<@_yqF`~&w zj%pSoE_FrH=N4+IXKKiDS4HNlK-a@9X#|HZ@C67tQCm{1WU!CiBe!e+-P2TMT{Dt_H+h?lI#DCWn?loWVwKZ=B^aiy?ZQ*SeK9 zI@iw_=VmmCe{{zQ&#VWnp66jKRIfq1j1u-U(g8@8bO2Y*FPkW+T@SclcYp{;mGvSt z>S+L$1yw3&2S1MPf9FXFlp%<4M*SM%S#&g!FhS&$<8`#2kSo3O%KY?TmBV>MJ(1Tw zb7Q>Z*1pCO-z4nQ<>Q1}lU{$NCqP@Si_kKD>s-!Qs9N=mdil8oJ&WPUKkP zUq=en)?onpU%Kw2?t^dZ@I+2C0QPoNRv5ojfpR_#r)hTtXfj9#U=e(B*`DFUI=vO% z3_#_lc&KDgr-3j(6=>wEDBxLZPy!nCqvNG`y-skmtEf*`*=HFW8)FP=Ral*@EaF}7 zGANOQ2IDPd0IK$7x01v=!(Gtz-KvFbqgoWr;Sz+rD+06tEHNmtzCYjtu3 zmg=AQ^+8@v0ER(*iILRt{^cy(ZjMU)ih|wHKL)Cy2;2TqCPB!o`N?Y5brCSFv0t1& zLvY-}ivH*M|K%?a<+0;jy}-%G1D)Yn2cUQU9e{|el%5BXT-FoHRHn^y0hqSk*V7+h zW8$(#ZcPtXJDL$J;5m_{#(jT4&|$t z1T*wW=$kEnD_^eZDF1ljbqs-K1l~Ng2B7+RCUKheDpQwwU7W7bVX#W=zx3BfR~Xs= z&C@vWpKbtm@VoC1S_NH&oL2{*%K;6is&AmgCo&DE5E^b7;xPKbdwL1*+SmBvV!?g@ zUylPu1^uO~dpoYaCeC+WNlsQ+qe|CO4+2`qP%#fw{Q>I%fpjl*Rr8!ImI7oZ13*Bf zZoz0ny~1Z!hxh^UmYJY8q@dU>@p}mWXUrkI-lLzk7HWPixN3zX7lAzi)M;(_9yIYu zUlZUpsw3eCoHdY*MswW+byZz(!_I9&`*>_;u1DzJFC!E!F@SdqinObJb26v7I@Voz zaR{`yc8mW|&Og_j?d>a7int%_;}zD)??T6CA%;f%&7cKQ)d4w*@E?14CzCO*u_X|f zk_FTcLyqT;!1uQE8<8G#+>&$LTjbfCzpu#+H2J?BIRkf`$1Rv9+yl(O8O9kV>%)N2 zHFlhGa(|E~@w_Yv7Zh89iewys{h991(YDQ;fa67@G~mzS@AZOKR^1itT9Cd5*uiz4 zgo*NWKVEG4o0+&UUAg~3mxkG;T8V%>>+no}+`Da0QV{hI@`^DiD z9Huaur$CF-Y=p$Sk8#uO6(L0e8}Kw>s1sQvLG5xiPLTUAEB?gCgIT=@a5|8ct+au7 zK|&9EWIFs@9@agK=7vrNs$V-4oVh=JF%p@lAL7Y+Zv*WJK)vP%HYqKT1HeEYt;qD< zGG!oNz^9qmteh>nrRl2oQhecsxQ&)@>V`6WFPJ~fWUyk^s47()RT?8m9sh1i z=@B4_7PiySMADk$ZGeY!I9-Uh^3gnKh5g|6 zpsxZu@&LHEJ&m%(dwWkCqw5<;+w!{_{LXx77X2|HpWKmK4uFG$of+KDi50io!S?ZQ zn0nxX-?h4Rq6u%!`X~r1y&hORjhR10_p$GcdCUR0P1EkB@@c{vEIMI4Lh$nw;LAvW z;kz^CpP-)c6qR6)YC;HDtksMeW%|-hoPen)CZqPS5qis!f^2s?Q)A;lCLcQ@s3%;0 z`p_||(*VJkc_B>OL15ynkvKn?KnJRI8Wgj9K{PTju=xkcQV1m z=BlEbI8Y6F_g29C_L(M)tGqhZ3s12ueUeWI$A5;4zx;(3Y#Y+9=q&2+rf_v@KaDE8 z3@n&Iu_Vgu>PTVyi^GaK^`j4N0CNNeXO#E)(Ng0e406NSBdRy!^jy}4B~f2Md4k4? zZE?Hw`#*vq!Gg+VK)d^bW?^54Gv%g0}-zs&$ z3}tz02iWLp*E3p4lvkp2R{iNd<*!GiXp@Z^U!kBk+XGnBOE@J3ICl;LY!!NY`xX3y zSR3|V&f(7=eMGMF0*+jHTpw$yW^()1d!P(SOi_hs*Z`hcspE7=>*uDW-SN}Sl~Bgi@qz5Iz`JraA3rBpou%5Q_9gSk*Hf_qe;8uKy)#4Sjd6vcIoZVE zjs%D<9;aD%LS()aO*AN8ZEE{&_yEivR ze$=|y;>7q}JSw?Q;VzpL>SekV?zYw{zyvq zivOs%{@sI!4JAZCB|9s~x9DLJ7dn)r^0OWr^G=Gr#-?$;6#AaajFPp<>0$A2DNT1z2auZB}q;qM3@So`Q`ks^B&4 zx<;+@mvhjJy7n^v4n~^E5*Y?s|3b%P(1g;@22pxF%4`3ukMISzx_j*hK@br-KnD1b zfKfRDlv>N=MQE{;9m0+p?q8R zAba&io&o}Yq)x5#cY`2u`s?(K%(0u@zH8@&=`D~9D+VG2j<;_ts|ilVUwwH$hMx1= zA~xN8-gH6L?Ko;|%=yQ->_B7a_hDq2H$U*CnW^U+s!yRm(AmixJpt3Gj+y~Hjzcor zL$PTvOXttBd12R#C~L3s^F{x??P3|Dwhy~u!l&lNpt~^xh(4)>)4%#N{3@2b=C+*# z(meJ;MpeLBkc}N88?SWMn~pc5bxgqRzrPPSOYF59d<`OIy=2z8vdK^QifAjb8URIb zqVn3ttTL&C=kO8~PSjUKLO8mRFHl1vGS}-B> zu0XB7ex>zS{idPfQkv(HMj9RQ0;l~#D|CGvEMHeCZJp$AJ2g7SO;`9&zFNDV-x!zw z51A4`jj*eOpz=Pw;!Ap^v@CqItJ4gZ?eepF=Gsc}X}Q93Fk_|Qy>m^Qr0_ae2@E9{ zP@ViWUScFwFk5Q!9{Dp`zJNGp2+L(-eBK(QI=GV{lWDE^Yr!3D_L@~>i$f6 z{|Na$w-dlqj6&hXCq1Sm9Kp9V@^Ct3AKZq?V%=GC? z{)0^*#@SCfSIz8@-J-tlPU#^12+KkG+nLFX7asmJhxbQscP8}(+*`l2`sZS;G8bYV zEBRJ(e3S_7no)9nl6jdfwAVrFHGL)pzf+MmQVmlR279`ON!M5RYHnO)ygmuaNVYVQ z=T-KD&?e>vkW1Ov}@I%lT&-Ps)Eg zL%q2J5=`Xvq_ET0l*a5>Jpr^OWn)5|r4l!T?l}cutZqLRmxq4knXGoq-9`kv=i@`8 zJqbtCcI-jY(RtrUYB2|n8?59BI0@xfU==QbW|ag<2TN<34DaVAHWVr#yuqgNl&MT z6Lggm*5*S4_5kxaT(S}y@^pjW!(%>x$Z%o{up@b;ySdx=LGD@%5QCaKgu0gM4&lPa zUwP)PIg`z8@p>;rhJgBo8*sTw*+z9)idA#F{$QEONAI2C^6A*F3qrfC5Jq1^7)zUh z$hox)==;2XY)iC*^-O4d3=gzWYKhUd>-NJ;dfv3|X~zWQmD^177n}8^*0@l&K6ITd zQZJ#&xpVr#WCySJ|Kjbe!=hZfzHNYXjz~#M2m?q93?(Qcp%_Sqw3MVXq=bZ^fZ`Cs zh%^e)UDDFs-Q6%WeAoEwy`QbG`>pRgzCZSHj2>)+iTl3RTIV`{>qQ{Ftt=BqH*ShX z%poOzDS(opd%mho81BR2&{*pbuVO3#P^Z>SY z2j3@2c&pW5?p5_f6g%g|Pf)4>m|V;{+{rVBA3=VBHo&@cbyIgCWD3M`|24?%aU!Gx7zE1*2G*h^uNYhyVj3_FhP3s0FhSQ)-`ROk|l7g zZ_WV=W;zvq?T;xL>%IMH1zj^hM7bMhl;N80(Zq!|3VSMh>Zv0j67agY9qnbzc17vu zD?lz|2z$Jbp5W(H%od5ATgB;KXpyKDX)24>h(@U6aFo4I2hsCEK{zkE=DJh?Ts)X%L?G7F0-w3;sU3V6QOsK{9|O%iN1& z7zYa>qL}_6@}j-NledM(+W^AyoOE{x)Y7DS#|}3*mevG2J_*3v;$=6FSrz3`ff1VY z*|X33LyT$=j~l`36ti#w+L$$XVS{&bgUyyyU>&Z!W!rDB^WAETX=hW3fE387X(WV-6O#;kJF^ z`zvWVH1?2Xtc0657kYx}n$_S{o#a7e6Tnbo5=-0mMgSx4!Hc4CIn9JhIk5c@}X9MMgO{-Rx!y;-mXHWaj@ z{W-u8q+{Pp5}YfPizd{wjTD+_?1OgQHQcN-*;L2ybO27+}@b1b^L13YVhWh`v<)U zMUbr(Gd|#X8fl73-J)D$CL}8lMK$L*Ru!F=$8wi;?OCVX`{dP2eS|Z1es5KlK4%>E zO`!fcIkW@eUy5Fh<0-8GXHH5v#`?lh&_DxHY5NfF1w_ir?0wVD1ck|yy|^Mv?Ml9h zIt)zUR9wSHX^>Hmn;c|%w^8`6L^BD!Cqxkwj~GTHaKqEf5es>ly_ za=ln?u%d2kzJQoSKH*by?&~hFA@uecw5)tK+(KyWHN?8(0Gfk+JdkPO-IP~fVmjzH zI`Uv`qjm2SYPRA@^CRcig07>wG%Lm?q3w??gLkgvI4w&a1ZF`8vv1q%L=PzrEdVgn zcn6ShdW^~{naNb8=A<(sJ+oK>=|chc_#UxP5f1vuo3xL&ymWx4-;6|9-y9)G{zN|= zY`XqUmLASf+0@p|JXAGwwQ)TCrJX-1z43Z`jT@XfGCTpoAxLzbm5W(>?MnNYpG%2~ zx$XTNLZ};?|JL42@Ts_h-l*?eH+SUm+H zB)f-gC|8VFHXy#ib?VI(sd|no?M8sReX{)PA=OXmr49hgA z&oaR(t|W{MC^~4QDedKgo%8gcRMEf$wIpBznEHG_Q4{+!_4&+%qi zBuyHcWx3vskhOK!>966IKj$Wr-+JTZm2_&2#Zto3AL6##?_xIQ0q{&5HTbQF>T#?L z18tmozw*v%{u1`O!@ue^%!5o1-04Hs2{v`%%eJ2i1g0_=*4DUb)2ir^_dZ0XT({F% z9yK$lB!7~G_n}fu_3pjQTxVM)BL(=i3cR=A3^^}=rJe(7k&f~a$)Xt6{U_#5Q=0?{ zdstH28`XV?s)fy|b&^}qU3=6mzI5hb>@{3`RlZ2{B(n~HJ+GiyBri{hb5)Yxpm7gk z*+hhaV2jmwYyUGQW^L|!vRE%7GyO^@5;sy>$#A>NI3xRm;D&4#DFjLN5 z0E+NCbGGBW$vOK%x8Z8?$J;H)4mL3!2-K?KT4Ov4c=jMY&L7FIhJ~}7L)QixKk+W)~0a?={vz+Vwa* z8hx-k)3BQ4K5`!bn9F=BXBYY<)+C@+wmX0u_nP|=8Os-LwzOlp*-tadvu0JPc*hgj z@aOG!VY`_VCB(Z>(oj5P{_;?rf8rX*V4`V&Y z6iu}GC=%DJ+;30Tvr6t6yq1_)uO=JSB4rqV1Q9GCyuWqBsF6s3k9h!b<9H0mTb8cFfE5+7BD%S-{#{^OeuA4!+cv(U)af+hfHSJA)aI zToQ)BmHqP$1MqKNq8>%D&XPpvOEq#RP9NJTnmStUReMGbamsWt(%0oY#79mDGv1zz zsl6V5-9!X@>lQ|b)T{M54%{DkYJrLLV5Dy7HPq_raW)KfP zV%U_7_l5l_85DpANxY58McY&|Ya}z~8BVT|3B$D~QEqMH6#{!a{4$*<`uc6ShZk6+ zX79Cgs9!K&kN&B>+36>Zx(NO7x?Jg|DAor&S}b|o;30whC2k0`dY|;gg?;OYXE~!Z z<+Cnj<#x+bRT^cwTh2=o1jXKr;v9i5#0>;^l>y7BX^l|#mAIyy+1ya*b*$VYT3WWw zLM8>beZz3d_G|)of^gS+)MszwwF@c#M8|ttWSTyn0r7G33hTsd8RgFTGWlS7$tFe! zl;qYJV`hy2WMqAc-b=f?9=4^_A4q<7B@%lm%iSPVv>A&Fig=T41iJoZ#>TS?!cS`a zl?D!W*D|z&jN>qjD{_eDw~%HE#lIm35nt%i*lG>))2vi!yr*SZ~cIi4>FmA ztz;0Wa(k}pMd)j+;GZsfA-WhkDZsyL8KPHJH@!+O+{ct1 z0CqeU;_v1CVf|X%X6v{|V6&#@1D+J8a(fnx4PK~EfDGF-1o&Nz2qhLvlJa5Jhas;- zZYkdovRp9QI*dD4b6x<#$tYH{l_aaXH5}CE@r9&b?xh5mx0^7Nlk{bEARR%;3KF>R zYn*_$x;p-w{Egu%-;{|$(>T+(sXMnaNl#ST-Tpe7;mX z|H`P3QB!#Hq46ZNlvI@+K6oGTh1WIrz+N%4<|K9=M^YxosiO^k=^`{s$Fs+~3~B&C zeB?#Lw$|7I@mJXk%<6F-0j<^J>dV7%&kU9F<_@3o}C%L^pjp*hP3Jf1Kp@f z{p(J=ixHfa{E@adcMSECHAvqJTMb_65p?gbisu1No@d4zSWTeay+~p-ghOEcm7NaoAT5?_br-gNa10XL*1R;F8EafgbSAvm_Ms13bct+o*j65#3Cn8 z@bzs<<{YIHd%jZN0W~ipL1V)GOrLfmm^bP{e{dH(GT8{c2x^%Qp}BeK932-?MfoCT zDp-mx3~_Q-rbt5j&mF4Myjg#R<*l#rg|}muK*?&fpKMZ1&7{fzV2HCKu&+#KZUwAd zdciS_T$!UHoDZ8X^a7KO8a2EK+1UoVi%?}!?{%wVfh6GqD2JK~io5PTC!ikR&%*F_wT3K_c+t&Rq;?DF7GjZj(-M1=v`Al~!3EQUGUf_tYrc`_4EK$6^ zxdZ&lzo(vH8~;d#@h(0R;_-1h(3{Rwa@GJL5@+?8!Rc+1M}bMGQ#3-QXe# zA5RZ_{Yxfrv_% zLm1)-`oSo01U=QOqL1lifIx?oi@Lm@&)RPp?r!EB4j|Oy%9rb~+u9wj`JbD$h3L|J zcytQw6msu=GFBzmjMa3w8c0#r@(y>@tN*aw=Qece<}o;j;6jZ)#=f|;3|W*pM)J;+ z`SSO&!IG4uJxTk^T%NCZBho+^c(5}a#WS{kRE$=bO>S^;<{Fb%WQ3Xiq+(nZswdDe z(>jQo%SILgWx7t~4ImKgFI&(%g$Vh&VM3jV`SX0(O_N!>NqEVX`yoH@+^mZOK&Xz8 zk(N1a;p)Sh1s^w3lV*G3Hfs9d{xymzS$(Pq#HR_-8_nLk{B`>D$X<8A>-oQm5ZGhf zvM{RdRj2U~FU4pQX?=*bOrqVUWe2K72j1>QfesDghnVN!7r&c_36hZ-dhK!)GGBYW zG82%vZlGvHf1xSjxd7EmmOh*+_gx^;)2Fp2y#OFNe{|LTeusM_;8Hdg%1)da542 zH|}Bg*V)^6)%MNvd`{!ym_RTS-1}vVS6-~7zYQsF%OM8<{=MGsoUez+>0Bdetv>5F zUTNY*yE;`b1)Eoj^@%+be9fPCUhiS<^m@cH4gHgRo9LbMj5AYiaUFkP0@ z0D^`c>g~lIuEqS1CN6Cnhu4`K5$%=(={NU?MhQMv(>9|&5%liY(b~Y*LxjMl8e4m$ z8F47?&W&kbjTaxr^UsocD%Iel!PYJ@Du6+FHDzWb-;Wj6Rpl!PIh$^+Jv18D&vT}# z1aAb1BcE$bXm{XVX)&-^b2*5=nV<>cD7PM#sqy0Sbp0V%GI>+IGeJid{ zwqDwfk`T}$w{d$B;=At~D|=gj?|O2ZFwAsaJD%`{NoH9J>^680OuFEWxlF8`?G8Sv zIh1U$roV7#beWI0YBZ|S^?JcKu{tXG(l0UutrSguD{@|AS)|%bs~;vbKDh}5Q5#ol zJsPLW5?i5Sjn$I)l_FZEJ%`;MG_5+6XBw_FCRpv3)U=Tp96o6LR3X&s=963Yjq8Ki z?tRXYqtCJ}hszW=DW$aWDL5{IHc9A&v6-83VAwlO);IX0jSl7JyC#tngHlCG%2ywy zJWM)N#Y4d-VS>gjtwMILsZ$A0vRbwO>2m!HG^rrB;^!Ak&4(t6i zL5p6cJ4k5cLtAz>^8wIpe1K2!>eMy;e(sEWbl}jb(rWpkwIVv$`f5g@f6IL^f$>?~ zB1oFAIZnA0l=`Ih)%|kUeWko&|KUwQPxv2tasz;(!9l77Ywk5`YoOAS)X}qDl`G$% zC1Sg~ZtRnb5ny!03|72`cn$3)gRWO<0KbKPDrj$jtxK4(`nt8gidxD&88E^k*T@(e z`_q5Zi&lJpu;gNHGn(3}4CE);7sSD#um?p_=ovWZ9Y zVzIrxw#wi&4K|x-=03WC`}mX`%OuW6Ymn*9tjA9W!+aqLK9$0b?6REn`ams8#G>p|LGtB@BH(O`k7S3r#3m{7`6T{c@RmkXnD% z0gIhWp0MZ_Sa6t~qGs)i6gzv2!&_(4qT}tFmG~4?fc0I$tH8=jPmNdd^W5jJ-)jG( zbU7t7<6!2gMxJ5b(eU`;(WxNIE&rc@&Do!U&0ArOdJ5`nLxr}6wk|mf-#8zAzCuJJ zNLsLF(5cwAMM?d}_opNOU%y*tFyHxMj%a(q&M1s@2jFFS2mU0{F!}y7J z%O??s<;j-6@X~)eZiuzPK$c|Kv@P_fDd682j}YlWGVt6v1^dwbR_2B2=z5+H2cw+x zy94&qe?1SsJ_vCFkYUmYi-F%?KmD%{#=o(KIC&Y5mAe_wHb;iuO#ov8D`A{l4lYL48>p?XUmxpW|bkOP;w9 zD1-An6X13{AAWwQ06t0NTY{}pr>^Fsr3fX>V!cwJ4%h@Tqr0FH%MLUmy2Z~$W{y7q z7fk8iWMJf?PO(F35_oBDzoOtmE=WRt{T2RtUX^P0A~ODT0h}}EQbz+RLSs1Z$GMM< zo;>PxE-x_e-87vNH4gPUmKujYDTu$HkERKYG8J9}>6i0O%$2qb^wb3N&n_v0)B=)y& zh)e$c9Vp;4%GiKOBosJW8o^UK0|=H-Fho@-vYVNXviRDN`*<33k`p{mPiUG=0pn5J zU1~j2YzNQ<(?NCtT=vi{oAUiz;9BG-)_)ygJ3Xt6T8ZqPaU@{GA(PL>=3{z0hS0kW7Bt zNx6Y6L%+)o?J_j$NnrH5Sx|ATyi_ZN8LhWT9x82p)hbZoR7>N)Ohz#tK6m{yaKiH!;UEmq7)${*FP(jTCyav$<9Ol$c@Od0 zb`7k~B*%+j=8hjiDi}%`T5d4$O~(I3;z zA6y+NNd!V@&Kjo0>oD$jLUJd*RCrmdpc5V{ODtNGG1;f*(PQE7#il;Vh9&KvO!~mI zC5kmz0v+)x>C#OX^zr~kdPE^j#(j*j4~R`zf$FvGb|pD=w&6Nx&Nl$SF?J>X1dIsG z%Y=PnK}F83ku66ZwaYFy0N$16`;Yb99!cDoP&J2zs)4nJbjYc6CXqZG@YRSLmHbKo zBmDFF@XG_nkYvDCF;>ZD!#5@m1Wj9`Q*Rgn(6C35R5xrk6t|K%E@_}m>J$q8E5)}U zrFbXgk63rc_}!x&Iu&dKKj`D}Hq%Qur}!ls*JayoAA>nt_Z5FHQXH)UYi>$i_$TA8 znF&xWE>p$61+s2@q?2qyx<*cto()hE>&|l_qh+7Hto(2>j;&Ny&wbx`hm=nHMjk{MpoXpN}{$ z#^B!V&_4sxd!adonN~x>6tr0t>@{_$#Z*i zz)0~P%~|{i)nhsNC{09{zP(kt?C26 znfj$S()^i^brCmrUlESBEgpe)U^u1-pN=v2GKQbZcav0R0}`j$^0KFO2>TsvI_9Ds?jfW(cV@y+vC5B_j`REl!gk|DQo8swaND8rsb6K{ zAU(Go3x!=X7$>q(fqT^bH{e3;yr=J1Z35&8nTTC(M@5Fad=X? zH8f_*xo*#Q@IM=uCMt#u%L{(KjNQb+sq~A;>96tX_dc-bmx~$CV&|@xhxpgL_8-o7 zg$< z&k3j--dAShbjwqCpD5^4`uoUDyjWW?ic%{|<^>JYn3q?^7|*a2k|F~$w2SVCyW#9& z->d`l%xwT>&w%g%N;$G%Q?P*$YVc1R2>n=_dHMnJ;=r|r0IL8ySF4vu&P@S)!w7(q z#k)oTcFEQ*zHH;HzrO|Mq@1K!6GeD@Spe+koR-OT0g^O_jCwGV&fNlCJm!79XobjHrrrVTSp#q1N;1b1!MNE~qEi&Vq@ROU z0HEO=evrB~aTebwJ+d-ZoL0p8p-oF|Af?5l6dV`h8%92q0L)}{Y!I?$tJVh#Ml>y# zZ!i;1GRrCXzn|Aq*Y+7dSp1UF2o5nqQYW6@24ZE-oA-Qve@nRD{Sz*+&s37~2cV$G z3=$K7KTzYsD1g+xgMM##2bV<;%(=i=4mQp>z`<*mQ*GPnVCrKNB^$~SGJ_lza5xrd9qwl(ilz$OQt;Dzg;>!KRwX+~{K z3JoRk;@o5jU0}v(}4xB^PCs$$UC_%Cf&|nP*&{O@@vfYMDuO)Pq|I_z#1ZM3gXb{ptPlTjh zYeBtJYx8vQ@tXn^|5vgOZcaGnFa205b}zR}3{ z4;1rlMi27a;+6a!PgH_c4Lp?OM0i!>xGz0jT4ud7M*na-@fB%VaK|Miz?(O%P zOrfzxk|p<74TDLG>2?nTSPVPuoU?|8xJ8sLS^X%!aFjhoH=7IXmk)mrWibX35O%c` zk8cAKa`PD8g?K?tO}*JJOQHbIkkgeo3`%ofvu%F4hyUx3<|>RC_)g8gIr&J=FohFmJPOHYO#E z9;r2e+MdPjU^}#6)L9WM{G=TTm%@Zl`&)BOU_B(o4F#xj%%K$V`E(ijyG1MDsJl%I zECP`+)2|b~r`IR_6nn@Y8ST93$<|-G!TP9B+F-xt?MO{?Kx)A{<5aHnT$5uLh{8v7cJVAqe`G`(+TihLPvrgan`uynY zbF1g4ty|@7adU}tUb=QFFAp}YR|;7CmIBzZhfm3~9?mJVgC=|yYZd1J3^j+6^{he3 z@;lal0R@lRs||JImPq&=-R^+icj+RbM*-6cuG7uGt=KbpaTCh)_bVPTDEcitzrDnw z)c|343N+ZBXsqOi_mEN_E?vL+Fg8Rm4UU36ikC-9Fw9v;aRs-yX}cd-y|o<8)3CH@ zzQuD|T`xuTU=DN<6Ss!H@*7Sm>7dPl`v_pHq*Ri{I!i$0%e1aH`59N{9@9T=Lu%3#+z1#%Zi#JLi zxV&io9(~pAQUx^LgYJu`^Qr`ze!rse@r9hFeX8fDU-I;to-g?|A$7EXsD1N(u0GlR zu4;ioS2a)LTd5Ks&+|Bq0MKH`NWWf%0l2uB5OipFc`V1u%K*9083->jX`#Vvf*IBL zlkr>hLctPpDYy&YdLy>Tu>govC3{Tx6JT>xNYzaN=JErK2I*Lwpe7E%aLrqF5GV$$ z!z{Ljacim3dmPzbRgLqR#gME)G(vX{uYnjBWqAh1>?fl3;5!^kf-N+&QD9+h#H{}T z)u|@K;xgD?_(;NzS#CQ$Uh~)l;M{E!lOzC9J*G!YlZk>DWW&uFhb)&}>mpFG8w2ii zv-`o_25=dOPW%ow=&sIpVK(K!3R&Ob_yIsGmm)gCF`86x(!;b6e#B!1)2Aze)LoIk z;<3P&H-SH}gLo{kafko`(ldXH#}b{TLVyh;3}*Es9t#B<_**~>bpq}Qi{E0w?pYCaywhjdq(=GZ% zW{Xq!syf9rTS!ww85|d{Nu2!~jKp3$8Cy5*>65?MfH(RddeCYIL^yX4!8K=s)cD`eg39Yti z$csRY;C+di{aW5dFuS$)04v) zP}PTFs>2lA^7$?B(aH&GI`Eud0(o^w(n_`JOxGtdU|Myn3E)*qZ)loY-C@yPNZFr6hkSwZK+B>G`%uy~Suo zuj@*3#%TVaxO=}s)XDKdC?Fb#`FDiNL}tUY0MU5VSJUf!T6>eXHoO_MyJe(GAVSmUY{bY;GAoj1Kp?FT{?0$Qf}Z%7UeWx9KLU^BDWPynV3|89<*>5 zQ;GIVC@^YZn5xO!a_Dw#wP+v8vk0G)yI*z-G56XJ`gFdJ?)mViU3&QV+4TC=<0*#I zc89sdWCfLH+t3!oIcM?btGQ_?$lbE>!f48*Bv0=xteq|D^Vjb5UX$$ha{_^UyC5K| z{NVF{8jz)J|GL0#=FWc=kOdkNn1HNffR%P`1MG2sg{5L^vwQA^sga}p>NmTg$K1^x zzwJ_XzCD8uRU`mQcIPzL&!6S7q)Qt4gg`~~NzC@rHjQ>~$9@y_=sH(XK1W%WQe~v{ zNs9Nv@zJMQ@9WgUlz7@}IwA|c>)gETAem~YH@l}oVqmD~kauIL=q9gOvDRl)qRN#Q zGR$6yTl71^D@U@HvPHHPZ~C%VVnUw!!cuslpObE6`n;Hiv8G?O0V`zX{nJQ!i(>GU z=Yn2Ef1BSs4)C3idrDiUc-U;ZU*aKK&$oG#;@N%yy~sg7{S$ETT9WWL7k6659o?)2 zlfe=G=PfSPL>eC*)iW=PIhYyg`X|l@ZdnJJb9E3DBU{%Cv(WRNP`xt(Iu^G@OnBsCqewZsKd}+mxf@n+3*}t%UCKI6VV_PXmY- zi|HVR2GsI(Miqd1&806O)a|k#>WjF8kooP=OAS*B_;BEoDB!x14y=CI*T1BnSDq2S z+bm0_`)Y5T#+ZkCH@u!6e@tLXQn_Bj)jGoA9llHDtCAMC8*A9LDkY~gQJX$XhL{ThDNf8uV7lc>B3DpT5m0{mB#^+n&OrDw$=;Q zsU;uBP}P{Vn_M`%wUkN)aX0oS(l{2F#uW7?ptxF=azWoq<5l$(xp7NZFTj6leOK~_ zth-9B%?mxaMBH`=wtRkf)MQ-2O#mchzj$^}!jhxJalNBdXBoSd?J?e1Z~M3?ZjJr3 z&@@klH_#0cb3~04cL}|zX=^CuF#Vg48Tl_yg z{EG+;|THNzmK%S{oe7IJm&IBV{c@po$y#ip%+sJ2=J4FB9-P?{77$U=k+i*LCX z<#w`ecBb;G=SNJ9m48LHgH%f)D)#rU9&I+M3|&_qzVB@AdYc82)4Q~Jd_cCDp^*MZ zKvpuPB+K4%13eNGrxXo#^4#-O+B?sPR+iC|wPU-G6th;)nAP*MNVkCcFR9YO5@a#C zE!5n>G(&0w0+2$RW-jVaZ0=y4^_uW^qxSY?URKl-w4WIhYH2zYHDGuEsQ%M5%k3-v_y45J8`DilZpG5!eb!xTxV8&ouNRF}a)c2~F5 zywFp}LTLrfjKGku3bO_QGxG)@2}6jtj@~!`E%X`s`vulcZ|Om9JQ93l#mUJR-p|;( z*~=Bn+!RMNK~JZxM)&(h-K6mi>?dY#O6n{#?GLSGdCES6$e1(YJH>3(llK^FA(wLAWq#qIuJbyrp0SAd0_Jv{}2Od4vc|Su>{*4)>A5i3ZxEJd# zfFuYAm?`3R#_{!}TQz=_Ej9w-vL?m<$&!G2aR-eAK@U347lz-hf-?D_{ zD^|5o?^M6{o@u4touBc~sd#62hmO0XY{a?@8@ zR$fKmoSGh!9|MEjaO86}ux!U~Y9Y>|bEqy!FQ`R6nmLKMpI8&>OrY2k%R;GiQV>YD;0_n>w`G#K;vYj*vnJ@n&U69u^S;Zw!a4&L17>y;V>$Zryqk-E`m-aNpB_VTv}`g=sT zFWMNsNL&J=l*e*BzaO+s-)0nb6IinYF3xw(XPHTr`oBi3d;AfQRc=wzXWhts(rLZL zEC+y}`y0V(#2Y+xV^zD|xvuKuC!3S~tW_zO&5`wQaP{96O=a93c4r^P^V(LI6n{eP z6y_K;a&xPfRzvEKfGqKU1!TDd^yZli{Rqg)CF=T*0a(8t65)yWJrhU2pX0s%EB{ky>|={?@rUilUn; z&romI3!B$``C1(4BaLJHQW0KJyXL2w8L0)v{Dy)+r%eThr;jAM$K4`gfW<{6`b7%R zCV${BIV!{<5h<99bH<~0>NgNIZbM5h+Qq%S5Di)^a`}h}x&t+sr zq`##bWZdYR$~phUTomc~p{Pt^CL8au*`dxfk&Y-rKCRVj?%)X z50YLfU3M7Q1qDHhYEewM9!>BIo!^hVJdcz?bNa;HT@-!N)$_4|yG!hLmRD_p%7DOh z%KaXrlO$|@9>Y@P3jCDm_&aK1Fjiin3+u>!%@A}6e zmx};&*B3Ugpl?W#>bNz1P3Jj4oQ%D*=N<2qxCD~d8_RHaFIeXPwhqBeaboowQvWui z`n6deB8)+FTH^KPe_JsA>n}Of?TG*GS@`8~0ulHT&9^xE$$r;t_+u!5kHl;C+@OX` z=LqTH#y$P0n(uUu6%A7?K-~SFFviwIn|Givz-+u*S_S+33HWbmqGtgZ5)QDaX;m(d zhb16liCXAs*dGB|Dd}Lb_s*XISzsS<=JVeJvH%AO0*CJFnTr@Z3eE}M4k`J^->o?{pS#ypoiB4 zI(=AcDj=C3oeIW+6_HzUSo>6JAcLMOMZYkZ%3f$huQC5Ed(>ocBXe~<0$N)YAYWMjgt!= zpu`gkv~A&mm$%lw5JK3LLcpTnN6gT!L7u_w3cvxLp&Vy0b|8iXjFn+I^+$!4ta5Q1INp1z62@uq4U_hW`~|JUW9F1qCX= zka^`i4so{>%3*EPEkp3bV|#)zPf`*<23<97S}l{xpKv+SJ3V+zDDK*Z>DaMx!?Qrg zy9i86^D11#^t^XAe_pP+&4`T^jiXqeLr|wZO~;q}Sp?l@t8w6tCL!7$O^W%DJ=|nf z6&R@7DW<2>$y@LUzT4t@Z)wkYMFg*hZ+?!X%*AAQ&T6zs^wZHHe-{{INwBBD0lu~g zWHO=bI<{3Q`5oYG6V|13Kl}eW8!BWA07GwbggWFJVKtSmo`U3|Pg1>Gn$wL-wwdm2O{+-kMFe> z)3>gWRg%xF`_UbR;&{}={enLw;CPe>P>=IMNw_TT1`TNm zXP4_gQ37 z`p~das#sru$;UcuEwQV51oE+ZcO6SH`BUGUOk`shwi~z3bqDt_U6rnK3=ED z(~`CFFNi8dfr*uuo7Nsh-%aevp&va?_9OB~P>!KH>dbXw*2C9-@;oSglpM)67L`2S z?&2&S$8iZu*DV`#K@XU^@fHG|PZdD()}Ca?K?iLQ?VZ(m7SIF_$u2h8^ASVvER{f- z;R7W^$+x%nx~I^-T?rsMmm4^8)=CXEaxUvUV{Hj!J;aQ3UMb`|P>$wLBz~9|fF&?S zPk1Mm8<3RB)eAYy-?JLRet18at9utfO9*wlS98G@&@m#KSsW~WsDQ7!pJY`D*L73A z!28i6A})@+@y4?pgumFt2H^&gTcD}x8f9I8DYkFL zF9OsQKYnPgzQG0X+k6 zGQ2Eoxnr~8;oL-|h0H;F9~-jJ1&f_kixfozMwXsM(C=uoltpZW%qr{5SZ zqI%4txU@9i&^wj(zC0sl^4+F)J2Nn$EtPkE#zl(cE#;+(ggLJKukDg2-TKiFIn^4n z59JA9-RaJh3xdgkNsq7ECZKUBCtk<}yiw%36YoK)>H>6LUeetD(;z?(1U1zjhoA#l zIB=Os3d}lgM03n1vqaQmBnu!r3khb5`wJ@iZ-H*~Ht1s49!sOURGciZmxD->(1Rs25-#R7N9|6ie4;CKxAcPJJZ{@(ki zP%JPzyZv)0mc*~2Sb);7_$d?%Ajlg_RM+%h{0POuNDCJb{}hS^@;d*wp;!P6|L0Jw z!CdqB|9L2u8wkaU`y&)fsOLv0Rt!9*z;5ZzpP^XFmMgnw=-=FyjijbEJy@7voltjn z+X?P78|{5(-TjAq!4S9?hDu!O%0^?l*3hkBHauJ5dh{OSUbw&$jOO=FW;@7!s^vg> zrX(0f)%3PSF_!={YO|v=eV)&Q2zb-P8^Xq}GOo%?4ZoB)I7|Zn%e?@z9}lG#gxfRG z=~}3o=-yD>tujx+*`K0@t%u;C^w&29ym!euW7>@s_~hYFCnV8Rf&6f@Ny$=Vvm!YN zc#`#iw%nxX6I2vwgTk$uh&&ba*XeW12&%0HbG(xu_b=;$<9&6(kp*1&6SwQQs)^gR zH3@cN3tjd)b9%TYb{Wsc(Y;Fxv#b&Gh2xGER@I8#0YxW5=%=;4ScNvI#P#x;yg;)R z(X5Au*lQxWuN~m2RcUwCL`uJXdj<&ha*=54x0RRoKtJIN%I@^dKG=9B+%DAvgT<4~*bQ);`(b}IzqJ5_qW*}y zL_||P(B0x|bmu+hYJ*o|nSzhkiSSh`VJ>#4uU@R~dmq{<-mJ&O=;JXFNexe7zkZ?b zd6+_bs2%l50zwB|Wf=`@%S<+KbJ!y8t8~)zkl9kc^g9w!A^LH;>q&Tb0HG>#7Ef`M zNlp5@SLCADc@loW(#4X_&5c+OX#cvgNS>W;(){#GR z#y^P{K5t#?O+Qz)!j9P<--wRc&F=%Yz0(+bR0H3m3)oE$TdE^2oRs>rs}CO44HHFe zG4>)n4^7l{Ul(;2*yt%Xq9eW!H|Bd?7qQnQf3rrt4Pk(6rGEwhin-V<6&N}~?6Mrs zHF{Du*ImApc~za0{^VzVYd`9nJG(k)*6Cr3LpGE$wM&jk)-JkeZi#TO-;_@?e_9Q%4`x_1HZqz=IQK}U;Q$0i=#j!C(HD~Q1tv8;{Fj2^`&E|va18fW4XQ}S@uy?;p z(>Iq&*m71VM66*;BwG%zV+kOUzAQ)_7P=?*VFDdQPl&LJQi4I$L?$Kcxj_Mfe8c0a z`}PrdYNSMQQ0hu@RM7x63a1Vze&?YByGVEQmqa{x@`qQ+fb2OE6#JMZ#lR9}t)I1~x>of+3{ywKEqoV+;@oho7LdlM9&<0&8tL5AF@%Jd zhQwBBO<5)&Bh%h!nyfcUA(QJa1{L0RP=Kp=8G|Uf`8s-bndz+K?`iySED(?0x5)I8 zA(m~v-wgtbgQ1{pDEcWpBwM+`T4C$}$yDhjsMS7SoHC9T*i1ViLEsXZuthMDKZDtb zO$)WPz>fb#ZA`g7Whkfzh-QLf%MZb=4P?8Y4GUyl?XYEK zQIAu`JKMtABeI*z_YqEcf4nbh7A|^=ylBdX}lBJ(QA~#|T#S zCm#2<&wq^7D492P0&zrM*aX>4NxS3}(07r3s;>d1XNBibIzLfad`CaNEBA46$;M2=VU!-ct!Eq+!vXa5uNZ$GJdS^3#I&m9O&srUkes#h5|%Xd zN@C#%)(F$z2b9l`P%L;;KC~|l&_qvZYHkte=U5*)OQ{ogDrYY9&+)Ycy74_<8BGL& zh2wt`EZATK3*-0e!9#t|H(t#vmzizhywbzokFU($%1rAC zpFhM-61G|PmoUu{fDnUXm9JvLmMB#6j%C3axruzsv2K0oWTU$Gl;91ubqz+ZT@Qik zggLwU0-$ZX3bu}O_NcO|8J+d=1wFbu4^|n^N6;EPe!PxQX=~anG20oO%e-g3yOE}> zMB*L}j!xsX(X|ZO`WK-T=TCo1>hL`OR=WHml>Jn=mJ&z2)xEoV(^_sw@&|S`Qao`| zEm*mUqTWSF%-!9~Gnq)Vi=9ViuCS3OEk znnpXzeI&%vrP$O*g;$(NMkCvJf<~I!R_CS-0uJnGC}FZ)mFu#Xycpdx**3k04lG^b zK3zt0E7bs{!|teh$582;ac=*_*KBf6sCgIL6hPA?)XnRhX6D@#oE@$5Sb3^O^$(=< znRgjBWpU*$>PCO4Uj&`A9Wl;vrA!I&0*uaHo*phQI= zeUBxpO*}43m#NbGP_d7SEGyzUsn1&c%czh&)ksiDZm8%$?<obpWzvGHQ1h+`*#c?O7w$4^DHQu;QsL5>46(N;8XN=g;wk!t=kM-X3uZl>AbI2Ndac0@MoIwA}JtF=(=qZt-co?TtXLAXz)Z1#4O3i!h?l4(Kx!fn1 zkA!k&w);5M-CTm%O2qYXQdqyzvuZb}l`l>VUKr`s%r$x+KB#v#>Epxs(g6;y|@JT7&rSqlLUM7lD5RK7dP{n2dtD(lC z>sE`11pIpxh-`$+D+!A5iuey-BX|ZG7Cxh!N&0`-JIk;xvv%z((t?r}DM*O4igZY+ zbV+x2Ntc8IihxSDq=2NfGzbVtOQ#5^G)UKb-8wT{=W(9>yvKgO?BjUn!yL~1<e5!^hU?yc;ix^OL#ex zne;}Wlwnp7zC+9qKI5tALzlpLT1s_mkDDvEufWcvKsco^jhD$xdQG{M-1bR6`J8UU`81)~ovNf1va&;yF_~&?R(lF=lbM zE0h*#jB5F}f@D66d+sC={iLx>sqKsrIk&Zy?eXUZwfB$PLGf`<|6~HEwS?{XW1j+j zD{pnjhs&6BsaNuRPjS<~d9^zh-8*{clM5P2-BGb%JhOA~WO+D?Hox?}IaQ6z=xouKEXN#4}AmLZhjX+AUO zKo3`^Ed(M=|8Dc4Ohej(M8>;Hn_s?meu^+9OI4}Ulh0TN}P_H~L2`m2s5)2l$q zGF$A)o4&m8RK14*njO!cOLO0@a)(0L$4xoKPLWc&IHD_e86V^nFd&P$02!V3D7KHA z;bBM-4KSyMK)3rE_&GxI@ndZA8p`FrwHQNdkBjKk0Apc)l|l8jM@~@I(ZTU=Dn}O> zA{w?dcVpc1?efcx@wuL8>*~yu)n?A_)3~5yv8_CN@C~QU0K9aJD+WG50KNTnAdkgr zq9HXhVL2m!lMy%uRU*fHX27P)XceMvxe5de!qU7~t{%&2%=zbkS$D!=-*Q9QtI~nuM>fe|{GTiUq(3_Q!ce_|PMNI7Ns54ZKpK`@#M;JhCRSx9UY)Y}a+op#n{VmNea zk3m8f1s?{!GXMvw>27o;J&WpOCfspCn}I)cna|__U3181#Q|7-Ih~ zISi3LGf0UUVEE4w4g<)nzH=B5x-4QHgeF@@;SUZ2(jRZ9yLwe2GG+jAoqz+`FtMF7 zPNW0z9PGf~G=L{M=D^x(FP0PvzX&nclt-wp5b3UhVWtJV2Whe|Ze9qO1CL`TRgvBV zI4Abyd^eJoK^D^QK@OM%4b%Qt(Iw9rPY}g$*{4fJu?hi3o^hnqIud5HTPMbgpfY|4 zL;&-uZDZi)u7MNAbR0ycqNn)2$$~S@{1XJYtgTNPzzO-RJ^{&XEwMiLr%>Tf0o1{v z(DLC?FCk*omtFJuodOuVhm$fWJM#JN(79K9SqWI;Pfu=)cfAl)REM=tg45!#k~HtC z2%k2b{3uW%3-y~%aRGM%rga9y#soNpP$aS<^%Dx zRS~slcEcj+{S$Q@q*G%xJ9EGSV8z$^C;rTRK{(YZZ_Ly0;2D_jjf1pl?57)FKPa#W zIm^X}Q=#$%#25ip=^0{5`;P*$And^Odq5W4O8`#d zSp~v(=NEY(c&Q^sx0VlxSvlna8iYRKYf+Bye$S4iuhbyCjvW#BOppKXZ-*a-SI&IQ z?-@y2&;>uBdssz*&}U%DQlj&&$OWC;eWk9#KP|C4Ugt=3y}q$<4b~xO*2Zqt;65t{ zU(a>uF9}aRHl|gne@r+YC)6Ns<4hH!gV4gWoTzw3eUJMUuIIN0*7fJ8D_JxiCg73y zo;kxP)hL>f?|-S1Ru@mHV4sY`ecR?sZ$?PMbfSJRml$)!XR11_*t)~L^C)ygj3-!~ z@BGfU06L*bLcjVk& zbn&IYaUL1!1o6vL2NZGwsBKVo_*!U-S|OA`Z|eYW`8ALxh%jSy2G)Tj^b>HqLzsn| zt7C+Ok5Rf?+}`ebAv^=YfW7}S4#Qrt4&q}Rn;-}|cawB8^xD;nr^lbJJd^Ctw;<6Q z1JS~lWvuf`;*jLDStXKBG6>Dylj+AU0H~UA{UbC6D9T!moQ)ZWCULKaH)0Pf0mF1vv=kn30bcI zUvi-cW9|$MFI}A-yx|aBO;P~*cpZNNp4yc6BM&BBz@{Kd*j~qr&k_K1b88J3h1KVz zZuvH>oE?UoY_w$!;y_OWY8cH^z!4K7T6Km%H}dnpX1@GId#d%8(y4)o#RLhyL{K&S zhRz26xw70i^Tc7#_30Y51k#QT4I0JkK zhyCBNh~Q+(JzOy@PT(&gFHUyD)=wodEp~{`43cUzgL&6(A$&4}1QCLQAP*oz#1K2A zwK^`3GvVEv!o{v5Fd~m%>Gx|P;b0_dE(4r6J04RCjt|Y6kgRC62vx2^eh}5We~IG# z!@ZAi5~eoJo*|yXjlP4wEa<#{@(iOaOACnN1jK9_tE0$xK=SXbKug6w`|xaIJA`T) zULMYnq1bRHW7Vl8$Es9iF#4Nb;IFYKSWO#R0u%_Pg-qu*CdkG4J%^zH0Chc}tQ_z$zZ7_|o~K|Bn;0c#woFvj1^H zRxkkBJpRLktVA{;e)aVS8h10x<3Nh37!j7?5WD3kxocTiDVLoX#w5=%vyqWi4^-P$ zc+<@Mp~Xzi8g6k#R?f)V7m+DQ^Y46W;SHqC1qe)q<01nD%0*=7RxotyvF-5huLukA z8G*1m42Jrk;U`<@=&pg7UWB3cL zhp^5M2mHpet;Z|M>!|WOo@wdgRG37Y|18LC62B5 zpz1J$;MwoVqR4g+I*Rv3*(;xh*TP~rTzBQvAnBqGUaqH~sqC!2-pF&s9=9Hw?=oNBqv7tx9#Mu1M9k%3d)t?%3qlJcur} z+S~Q}`f_)JZFqJvoPs9IOWW{*fM=x>$S_?%=eGvsk5b;nCQYZYG|O^|ZMV@5Ak-u~ zfGM42z~Q^il$+Ia?~~#Xyj1rqVISLm*)4Y&38@=_k5fd%GTQ}Q{%vCS#y`nbgo&^Di@&rygt^ub?;+ipr_`h=hR@4slw?kg5t@t6}|`D zqZIswL{2D46XWBPPfnf72Ez`wgjYQlWO;R0ryOmM*VB!w)EjPnwQabWXoIwA$3qE0nTbPuZvxY!@~Qce!~&`@n5P^-Y5Ky@v5xFYqHK#5wABLax+Uz z^eW|7TF?3p&*cqxK2PhE!}9e!?0RF|Q9U*St8!0C%-gBCK-jADHHnOLgg9aPJeaj-4X>7G@laDY zK;bFY-}p{j!m&oufXjF)YdxFa4t$bkDjyf;(H@hE=XMCG2wDz@baUsts?8XTf+diP zY*N~#9A53l#*L~)Tos!U))oYUm4ejvZ^IOa4S zPMF)1HU#$FX^7$A+l^$?${5n*Wn>Yrp7xJVHLQ12vHFc@l6N6*=-vX2YJ?ql5O=y; zfz&s%_=OiJ?a96O-4obnZ+$bH;pH;8Mc`3uw?=<5BzyHUty=Th?3$p~gfphh zCPCO(gQd(1mf?~Z12N6Lb3vTz`MHBZ7eB?UtrZ(1=-g9 zTRv|-KDtr~U(B3t879gzNY{nNyNaMZh=mGx&rau49CD;X*u~}aO3m6UI2$_J!h@Ej zV`myBA~T7ioWCCA8^*&p@~GV@-gIC6rl=t&>Z$t+|KizJrQYi z>lWYP4UgA0-zcFy`Eb;#rvEZ=J8|EW zLjbQ!f3=6(0r^dB&HJRMsjRwIsvKd4&N2zEa$EH$;Z<(eZ8r>BhoEH4Gu`&s5vrlA z-oMm8dVB<{g9u=XPG`SjU*fJZ=fU-QbVA?f(gzBM1jeC4ky(y}%W2r*&lDaGJOd}n z+UVt~nawXwrr!gyq^&a&yliLb?98GS4!B+0moIm+c*^Bvhrgmt(1(`s{xvu#C8F_eE5nCE|Sa z)im`D<{ne&vrG!$SRAI%z{$OO>rg8=UyedO0nLXpyiJnT6%wy@4wFN9Ox2Es*y;bxN|9U(k6s-?Sbl4*^F^5myuX< zh+{I}Tf(T;fRfHf5z_LR2=z~u>m9xBQ|JJ8FniKCk17XUhnR@t;&dG?`#bA12tEu} z8P_x<^YFdL0-cdY$D@%snMC5<$wmwzuUFCr@Zgqmt|~&wiY9<}sj|2+@Vr{c2#X?Y zpwj0+N3$4BZ{?-%#C^Ghv#W4>4m8bY=rH#Nq;Z}?uFNAso3~grK9!$O%=!?TUQZ-U zZN$=aU5bcn4OiB>e6&9&;D95I+Vir}xdhoPKy*50vRFgyhrp6nb;41Bmm{wLXwo{7 zOX0S_W=oZf08Hmj?q1Vx!kKxf53D&R^LDoJJ;ROiD)Ka_o3I(OhOAgoCa-~WgA!0D zkIF-KrW(~}yaUGF^a5~#>8GUQ`dl8*1qDn^dO+8qDTjN!Y{f#B&bh$|0H0vn94LRt z<|sOfSaL4h0(cEXD0>N^Jy-D6X2* zY0c$~R`dv?+B$1eEou|0@8vW!;G5E41vr!dU*#oIiM+hS)eG-OTzj6VB^s6_36MBi z*pxfEIdzr|ys_UM8$VCo(YGHNQX`-D^kHZ1Ot+TN87z+vB`PxP=FLkfHQz;=-|lwq zR29X4=b?Zo?tAW>+oQTzbU9B2OKH~Lig-+7h3h_bNm9-R=(yt=xBLgx!lLKy_Ep(j z_$qYhjDDK;llK;W<$gP3AyZ|1GS0Xfy+7uZ9QtXgQGdE;F1NY8Z}xUkNVq}i>)QKW zQwg`Jp}=d-H|i$Q%-qgC94Ru!$a|ST#79TuXT3A9;&)ShyH=rfS7+R9_V`>Q=lc`O znMngQ2^6hVW0k0cWM?a_ax9$#x!DG4nhqUi7mW~grpO`eE8I$oh{^3|%h6esqBh=r zeb`KQjw%VeDd67vU<0X5@)Otai)8l42R4N!X|K{z?jF1@80KSi2sYj%O&(`iHxQ|* zcc`@|@_1CrJCyL0@3r$H-LoY>Q7?-o+=Qn?Xj`pT8c}mmHM3YJt;Jcz$5uEV`d{o| zt6AY6yw0oSOCG;XF38Wzqr%?F!D%&*!Fw}h0rnOH#^Z&C5|*d!+h>mj*O|;hrc#l9 z!jq|Gf_8ED_Gi)lcWE=I6EdIFjpMs7t6d15C0j(5IvT?ia}>|NxVKcW)m42I8tioH z)k+Yne;t-qL)od|(;jL5hSD-YTfa2ebSCfymm~dRb%t!dp^Y!UIow@69DgLlu%L@o z93A*b-!pKGgo#n*X8SeWt15I~fujtGj)4%|GkZgb9l#(S509C1{Hf7=eMy_~y{U$$ zH&NoGKfmWTw+yGIC+T5bz>H@{FMYbwr-Df`p^FT(z2q9H**aKH8$BESsofz~=H{)2 z5L*%c5O&7wCXYT`{92sFq0?Rg$5;tBLvK`GBX>Z3dpF?jE#cZ{Nzt4-dN)@RzKb+l ztRK=W<55z&)=KJ}Dh+W{`S_@Mh<#Y3*$_f!&WpM9*~8u@MQs^Mh#$-uhx~P;S(p4p ztpYS|iC;2Nk?p%lCe-ju>60eJ9T#{>LiTNx*I7i;D_IGtd)_w?P|=(d zs>N34ts@}U+ZH;Fk2UTnXOxWd_2DGZ{-8bERJ|YK7-Nx8GNGm?*I5=xeQ|1?;Oa7O z0KQyAkWQcn`|GRg7p}{(Mh$GP-%~$sV)s3K$yueA&{@4+ask=Z+9_D;Jj3K7TJ~llI=&9B_@B61s^pU{#2aJ`I@$(H z!O%vY$F^d&?Z};pX}Ob`WsQ7$33Xn^E1CvAsRwnn3HY11 zVxH|UlH~GndM3Gkv81G)_IAIl!a?Gc`N$5FgOCF=7>~SkaX7tH^52R!RlCSghlEs7 zN3mjEO!aO%cdfNHurGLnDAKBlc)>cW1N=!8f!lSD?f18Dc%KxfzM)tl zxs~}4x{GQ5*;os7*UMEeDL(VLep^vRkJfQv-9`7NNr?XZkYWq(Q!@W-v~j&w7^X=l z<6!W{Ns0GR)YW}w9|q#T`gtavt1_if6fu6+4|3ueJw`&ZNQi11?H?Q}bb??s-7lLP zeH^tkk1qGLulI=L(0BGgb;X3QZtK{IJ7V$PIvRch1HU!=OxD6{_Y zb@?;23W@x=#78t!avLK~*ijfvPeD!{Xg6!?@6^0_K1&IW50X|6%Lq8u4>{NvZ*-n< zNQeED5&5vnN;8$S1yE7XP5LhDTM*)x7|iOHSvU@G)O>VN8Ky8z<_#LtiW)X z;@bp{kD*O)6hxz>&p-;$-`Mls->5)CC?V4LP-lDSYv=1O-rd;gjf61}RP(d0Uwl7c zyh=gtuAO^6Yan2gtSC)A!sTuTRs`OO?nAG+4NRkr_H}|S$ee3<&21K4cja}+ni(-| z#U&`1Lq3!0NG9*iPj%yFLcZdYh}n8va$C;SCwPXft^rLwKQ)ZvyL7Xh@*JDxaLCvX z?WSK)())OxfwRPvzwjEX;KavT#OFbptUCDo z-CBlxextli(UZ9|93r^Qe1srvS7wJSrEA@Me=0Zo*jd;KHB-LgX6TYnjup_X(q4jC z=5ZE6axp?h-XVM(e=JYkK*~`)2vy(J0Sz2DXbM1j~?jmjsNnOvlKRy1tZQ)BL zwfvx+uB57?RO$aJ@$CRbA@+u&Us-s3v`rMuG&{H<=9u^8^xmLRVwW23aiO2!rs2+o z+rd$wgfbiIVut~=^F~T{^`oH7_e>`rg~u8{woPkoAaH;99yt9I?6>H&AI>N3uSO{t4X&e3;y?YkPO z)wgxQuPHY2D@nRbLVg5fS^Wsef(n@y02TiV$jYgEDHe0;Vs9mkYh;GxiF*`zM}?(DEV?1m^C4IfrBZLkARz1Y$?pMK zTu4Ax+^+#yn!f~Oxh+5Wdq5V~e-e-tOv)vnmx9uPI`Z27@!FG3xwD&mBCLdjxRUO- zK^yIAi_`z4z;Mpe#D@kILq8vgRXPp{qA-iLM8&>1N$5eD{ttpqO#06?E;BK;aU^ml z>w{c6rnnlW@%O6q+%a)ZTxGe&D-L{qt)_GB4L!r1i+gBt`1a@&B3i-hm>M$LDCUlG32R1o>Kgm#u1D^0!91XgWyR@FrS82`U#*-fG;h^h=Cbp;?p_xeOIMsZG zAMmD~%-LR@ybmXF&v2aV_t^!+Cgru|6wv---R(b3Ivwa($IE#dgVYBj7R#zEgyLu= z>8dw@4+?KRWp$F5T=%mE{X%o+fT3#J{?mQl{5nCbBYSLS%lw}n*x(t0YP!$33#4i< zM?7N|`HUB*1L)_3UK^I4nY!W3;(p4Sb;O@pWeymyU+RSW8NuKnXq?O?Le+QjDT&c> zE1wZ`K~#49D}(-TmMYq=t~NB06<3aI=KC3|4Tc&~C4G2eJ`zhXf+pyEGn0CJl&{=F7hRX+V9W#pj+3Fj`_2>%M)kI3{FT0S`|pBI2C>RapHDbD{My(^ z;$zNfydKsGynC3YwCHo2Ll5V063oMdT5w9vhGUopwhOznOu4b_^WER=PIR82<9ZKr zyCCXW(LwdAQK#q5s5GCO4sg0|Qdh3GlOKO;h3AaVl}3-NyjO~>AF`!bIA>#5Qs2!W zOF_Mt?f`c29$W*XhRi}+ z<8(!4&oUwgS$bNT6+Ix?%wJJYjZ?gAYp`-RV!b^+)*!`ZpCaGF=nz^8rT3mKK~4X)gCyZT6-{|bV* zh4urj(rDmqHIThk$iI}`pED0nX4;z87(F!pN%ARb@w4Ppy!dyL&(juvNj|L^ZM6*k zz2wul@xPUP76O|8A2gpY=zr0C#ziKuL;WeMV+Wug+e7QF8qzIix5V+emdd76MFI&t z-+Xa@2Kk6Qz6EtFe6o=1MfzX)STE&-k$f!Dzw)sl6647)`B*i)k4b-W*4_<&g`Uyfwt4?hzr5y^!c_d zX3$wth;B&Ub4x~Y0M_2!8kG9IBxdjk3rGYr;R0GT<|TRIavL=hM~Oy_m<6QO%RK|1 ze8YX;qJ8crRe9(M%x^o@wAr4QdJO^cd&&e6?>GPnHac#>oewp#+dw{jyXY46t!Mq< zF^>4Jwz1(%+PoCE}{k)&>}e&kI3&YE*uR8GqiFrmR`@b{IY5MGcF22 z>j36bHed3Mc>Srr(I@^ome5*n3Ccy(Hb7y>0Ska^M+5}3my|VZML$*DlZt~*=RQQG z^dK1)z>lhMyxO^Y-RscZ1$x`l{YOv$y#G3(--`^RC@p_E3%aO1nBohcpArpN> z6zFmRag$%O9_OWH8e>5}MM{rAEJqzjEPD{VL z+vY+0UkCqJr~msONFgENZvFzuk`P7rgh2QS&HSLPW7bt0cM-XSY<`eMq__ zGx^BC{%8|^^EjWhr;~ppX8d()C~r}M>H^^wwnM9x+i`&&ntc%nz#B<;0%_%Q2)5#G z(|St6VG#-~ax>P%_I624Gp!71G6>yJitu3fwISd-nvJ#o1b_1xz>3T^YYrBz?Y?!3 zw*js&Z4ni%4O%a4z~Q0PZw?MeD0-9$Aphil-1W!p+>MWkP*QydEuC~1FKEVa0kU%j zBD|iy?%;0g^nH$GPBh){+;={%9P}kr_|#MCV9uM6SGZ&`B%dE7^zP(84V3Rj$TjHN z%f489NMaQVVN=5XC~}rSKyV!|Hdp3aZ6w@qhm*I1c1J4+SU~ut2mR!R7CVmYBt+_jBg{ut)N2d? zpns)OaI+i%3n2{gDu2&0hXG9n!JAzoS|Ym-ADqCrxV!baJ0%TrRa)I3wx-bF9f9E< z+%q#0HP(+5*b(@$QUCOKQ-UVHah(UwVg~xMrKEsnTZ1NK+hm<@8o-KC*a*>CB%Sp+ z0E~nH089Z89R`BTY&`#$(W?-b84Myy3W4Pos|5_&FWTCW0cc zLB#pj==Z;7(@Wp&2Ywh-yqDk^$d$2&d@cr&{%mELD%2@aQ}RH(1xm9R&@$Xfa9iRc z?x$p+HOE_@+!#!gIE%a}KAyQzN1zo2l@Qs}GHpSI)1UW{zVK~4w2PkITxECP3frJV;$2QBEvAvZErk8lbC)`t@n-#Rry@y?TcphJl~+TA$Pi4XBgDR zIaXKvn~zgFdHMJ6q0sv>l%OSq=fSRB-hz-(M&RIH-7_=7-Tc$k zm6v@V8ctzeI^nkQLD?a%W%6L5!wYf^5LL*{@n~9=hg)7E2Y8I2)_U32g#Q`cCAskf zWZ|_yq6uL+R7=nm(j}iFJ)#O6vOP0&+~fCG3TUPPoE8q0D5=Oy;d?=aAc!@^BY)$c zB#7DNTewo|=Y6A+YwF;9Cz4;-@K5=L`B)1eA%zasJueAfJxtp{;huIsUT5)o33kZ};<;wM7vE?Q%ULp9CwB;3s&(hL9X@MoW7m1EP>LTZ* zgFOzv2v+513CD*tAE%q1JO?Dhud{8Bsb&FVr?x$*w|gKbnrnZh0Zp!P`aD{jvq6;f@0Sf29Nq^ov7~?;C5sm()ZMVD z4GeEYvcc}SpfcvR2HKAn$1ir3U%Y2JLjYMKi03y)+t>(|sjN_p?j@Ll2CB#ji5a^) z6lC~l0Q=TO3na8mH=Cv5VhJRPLiiz0cQy5C(4P>vOx?y>zU}-x!F}yrE9xAcc{lmy z8Y)SYC`+>ov_;dvEZ{@4LP#gAIMwHK78lCvkv-Hmxf+#FM}KIj{UU;IEPeX>v?RtlSMrn%}Clo(XG^S(oKqLTRKmx>RMLm%-cfaK812SLy0@P z0rxppisInK#+*}voxfk9kRi>$s#ng{*yQY{g6_LyFF%(CFldrUEsv&Vij5=1o zMiv#Lp6%+@UZBoH?@*lk-se!uNiysRwif4qfGJ*Dp+in)cJs@{d|Z(-)t|E(Et5**5`FY;w0RoM8l{{(@Z(ZqTDjM7i9nS0|*h9?ZW- zI_)z@-zr!X#Eu!!f+0k_Ll9U7sh^K7{c5`YYgKX|Sw8si5=EkgcNKCK!_!P4N3Cz#0SszxmsX52qp<#KYX56_ z_5BY!F@nR0u(=@PBS_*293Gq6V(R2|j90mtCy_3QL)7=6d5=gVEHiI|qhmU3eBI!2 z6L}sjEUa2s{~@^Qlq8BNor>6Eph*aN+mkJW&fD2@g532D$m?z(;PV;cN{wf4OSLpp zOz)wMPJQy|jMRuo5sUog)-n^h8}efo{8x>FR*zv#riwXrb0v~Uj>hE9k{aXdy;nUS2d!xVq)Q@ipz{FD#6Lfz3wfrbasWG?C9(>|YNUezkYNF>gauztVp_ zdF1Eu65&(#&A9Xba<1Qx`v0Hs&qL;aemlmKEHF_mClft3qi1Gjh&AuI zx>jr~jtqQ@`}(Ao{X;z|#qUO_H#;SsTI|4$7*1UNT$7=a0Z^PC=uH(ObywenP z`d_K0iziD>836DZiIGR_I3|%{?qWL81b0t8`s=R!bfkh`&PIX1<9!0(i0kHpDVXFp z#8+HlTYIER;;izhmi<+o`ETbbhR|AA6j{Im3~rbaEPCPR)aKRA20OgE(aCA)@^Q>p zF8uCR97ok7rpyltPkjClS4`#pKmS&|044bJuBUYH?@s0ziY`ER^U?GEVRpO=pQ`L| z{ceJXuk%C0{Kxxo%v%LM)t{OB^xHv0iFbzbfB6X~#bH4SVGLQhr~?C838G0iC%n9n zun#3*^v8`|F7^HSn$L*duPvRHoV>Du+0<=&EBzuKG(0mV)G^4RMPNl%MRuvNy z^Qqdw{ADZzXv1whoVb7G`y)OmjG|s*QQ+f)5(@%-;xlJlMPJ;kh>Ig_>*y$fVjr;^ ztOPiQz_n?D2)qtJO;-Y26PN4B)sf-hN()=^JN{7V7y|sQHTYnva+UqNI*vDMhHu<8Rp#2?_{;H~>y5hDUIW`Tot9MPJSu<7|dA?0G95sUlfo!*MP zt#|gM%BkU~lj^bk8p`23JFYN3U;~@<8^BxVzzSK*Fbeb5i%Ed(>abLACnMC<0cS=j z?=%KRVzKm$3^%+zz$-(F@PQG$2MVDEHVp5GS<7)S2v^3#QVmpFH)`JJV|g1UYbSL6 zybww%f^|wniMHRo5OQFHmfkj;86^g|QF3mj!_PY*jSF$u@UEOp6s$`me@-V;0^wCI zqRHreCX3BIL@I|M_|#e)f=X5%(TD5iQ5`UqErJ#C+t)4-54x#ui=Nf|bkP#7%Rc{M zc7zQBW5dyF=O;f8&^K2Eb;{q^xt~S`UQ!>H-w6pNQX?ZHSG44QXCyKfoE8q%O)2Sy z7_sRlSK<)8v!r+Irh3J_Ol2mq6B0T0nOS0dia9S$M_f-)uyE!k5YvAh#Fi?KNY53% zn59Bg~RC-2=B5mFowp7#dhY$EyW*TX*7+z8h(VW^oomCb=^cy~7u{C;s@M);sO z#tpg8+E=cY$&T6U(4OG z>xaRlqjy0iHS3O&yje>K$}O}QY-U54F`9?*#Yv}@iBaddtszqVG!HP0jYlB7a1Tu5 zoMpUuj7pO(^;mSN{ zv@7gw<&=(_Wj$0pxecK91pqD-fQi)}j_^YiHtKa-4PhHa!_3=*Fb9sjc(1M$k|l}M zz1+=8)LJlbFMP5bHhVn&oN3A}xn7?5CAI?;Y_$|7U*2^ZQwNnWZy4;!(v)AA({jtJ`7h(OzZD&=+<1pYx%riU#2X;l`H|c!61Ztn_-aJ+}Ctped`Ex`E4mPsXJ() zP>b3yyZOLE?MQAf7$)S5T6RoM@h2B%!UM9x`i3LTs!rv#y?i8s<^}7K*OwL22X+0) zX6F`xy06T9H%syI z%1m?XbDgC?k8R6%30{fLD>VK%=ReNL24u=^f>mO(PISV3{Ru8P@8F^@iPBpmh$F5f z)1IOs`DINe8wc~RExY^oRf_B^YBD@2cMxuYr1=#FP7QFQ#zRa}dXkiqUskR=^j9il z3ZcM3Zs0iI{~qGY&7DSVo29+e1p96tf>&`*f2h!~+A&2fRmt+4h1yAZb7eElcTfZD z>&)D=RdSCoIEfK~E#ZHfV#!?BZ2Jkr6=E^53_l7mn2(?0hZ#T5v#%@hqguU#WU;jX z#2_4YC6PVIGNT)?y_cY)a4g%=wzxgpM}Ery(8|}| z$vxg**K6;v@xYh#*7N(5nx>UhRxAG^A&c?4q58#H!$?gdaJsHOx+zuCPZDE{G;d)v#@qtN-;*4xQo|hepSGK{4 zIGeKw(*1H}U)n5`58sxdlQKT0sF|gsJa3R?r$pkNc6H_S&$nw|0>-2lR?EQmL3t-c zkTXtULq}FOQd?D%T!igqWG$ReC{do^7dWu6E|E3Sv6TCV&Uc zTroW@&E;+SP1y(TyKf$@o5V{Li)G8pSx#q(^x?%mvzV%tzxZ;v<2tJNT(_{fZdR3= zLNjqK1FzzhQlIW5Q9cU-T*hMBIpC!n@TbcpT8Wdpq$)?7wK^x~Bqi1Qs^lnT9#awy z3g+K6sS#h4(TTqGCUc7OFBnd&Wq*1h@#4?Bk=roSOE5GY{uoqu zDM>pXoM?mIPi)qS;=3vRulg=LKfCX>5}d_cTs=dqtT82QpjK+NxV0(co#xo%8l2VD z#~qH%i*bt7MD0kv?j=8R1|H`^(!;Lwog7Y=@Hq=de=`fW3L0(vfZ5c6(7cPUhuf)Fh$qOPsKA_hOF)j)-{OVL)nsH zyVo@o`zG<-tm_&~!$L|1w^!uJRI=*jPqqgM-@=!);dwFj8=dF&86DlU7llYV6?^ABr9dAvv2xMo*Ac5N;Czx@aa=tHfT4?5_ zTuP;s#=NkZ1Z{rb>NQ+-g%)B);Dq#H^i%>XU&|r0n6;SJ$jT~LW(3TM@-L6} zxyECgtgo%PGfAPv1NxrDOfHe#@DYVEl%cg$FT9%0w28v~Wpi@tE^JOzFK-GXOIP|0 zlsDLn4y)KqO2nChIr;fr!mZ#$RtFe80-! zvdV8{4Yyx+I2bn1+bHJoZT&!SVg>EzA@?#A*?FuP&!r#ko`s^9FhLzR7IW*Fj+4`rqhaS zE?h3htud$AtQ$vCJm0*CRa&KlQXihq9CL%RGWj)dmrn?fT{rJ{-k5>b*T;)Skl`j3 z^6lHbUbXnT5`a16)%W>*L%g=tW^a@+v;4Ezh(99X-P_omKd&I~*Gi)toj7*v=!luy z!|G2K*Fu%kJ&iesr2|Qp&y=_BS2@Y0x-MT5y%V9KS23ej;4uA)xH)*8W>qPfQ?-1D z+L6@ot)pG!^XyJ-4Wf~PoR2S6lCf#z6xnF9@|}`HMV8M=CN2*xw;xCE!b7b+&Spqq zYSZB&a}>XR$~a-jO`rr7<8u;f*nI+7lsiesFz-1z=|iV^J4IlZx^dbTUif546S4q; z@~||=jt(b|NGA4YZ?J)HaepZB;C%I3cwSKX0eC2$z?%UT;7iSghHW;mVEYKIo*N?} zWXpyjI@Xqr>H+V93BgNlQzc8?tk@entjXr5*pC#aIO~z$AaguUuCBJ%w13GIy{(~QhH4oyh+La<9?X+(w}#WDAJKl;mW+n**0nrp)uI(D8?I-z;%! zcx-&ow>p~FKDr>V+Z_^=Uk29ieK@`9q4dg1_x8n(QrSi^uCw^eqNJ6u#1FFh?D(d$ z^h?*;JzD0-lWmbKH|A&uBKQMLOtFH+gGq(#?XRMvqw8QrT)%!jO2CU>r07*{E(eO) z?j}1^``+GOf%ODG_1#wfPuuh-1H!%5=)Ckq`0&p={P-)sUY9_8**ZJD%6pc7ezh>_r7_iH z%%d6Y!?ytu1VY;wUMm>e^=GS(`8TjpX}X$F$N%no*sxyeaM6-$zWigH>0CN~+t$j$ zLd4jZZg_YY#uvpTyx`t~sbF=e)ALN?b|an5^phLGqqpXMjLctdna(JxVm|2&22Hs? zZsf5b*_~1Q&hx$(*rHtE$?YB)c?>~WQ?QR>-MBda^(#^MAD7_g^OJmbA3NeXYDVnk z@BdfOmLT+Vt3SCbChRloqpuoMqH}&6t%ApPx|T^VEo$Vi$K>aOc}|_=GxMqJ%iSMC zM>Z9eac*gM*Y(@RM&0rjVp43{Q8QCy3qM?Y=sL&E%!SgMWA~(3` z$Qds^Xi>tb)2I3Ge-Ib>!AG*^F;TmQhaWwAMxdyyOyZ>S^I#H zo}sQVBLf2f7Y)-P0>NNdoraCDxReyG2J^s!=cL6L_~JA%3Y$4TpXoWdvr%se?gj9p z-_fx^85VDvO_2z{j~BWSed`i?7*~oS{Hk-e1@~HRk#lGKxNbYbNiR{`Aiz}*^aaj9 zWXp%VCHF;h?FNu}PHwoq_G|{X;m)zet-UE5&cbT1u@?j_PVn7p2dBR7$Xq|ZNUb2H zvZalQs#g&8F5xLfK*q;)jf<>3=JZzZw;t^s&VRUqT*$R(7&Qu)R8E~bMMZilrKm^| zG>S_XU6&NZ;DEwjd>}iE315b0N4>$G9(F%~?cm@by)mS7F1APiOGmgMKS3A&vk)h# zPSqcS*AKpqLB&i)7Nz&5;M*wEx?GI+)W~stHu{n&O>&%AKOMJ zALmO!#meN9wokykaVh8CjoZ<=+1bAP?93fw`nY;Ay(1&$Jzk$EbZqw`isskW?DSKw z_LrQ!N~2L@66`>CFPh+3QOIY7B-AF_Bo6}%{t87bO!!6LxMWfE3A^~&IVd!KDi){l;mTqux+e^*r;N z1$N}kQ3i~?rePwOTLZ<}{ixw% zsI5%_1rRcLA=U^fC=gb!KCwRMzueR$=Dr>~Ap&FD>dhjD1^`cJ`FMMkWEAryFA)SZ zPX~ylgnkLcdAl#FAiqCD^JSNt-rF9ZewN>knRYlAwFk?D;&#T1-aC|6;jXaTci*Ma z!SCYNd)ig-Ab^Qoj_krY*U5M{2leNO8ELZQ8>R5Ma$>@jl$4q(#pN5dy$&31 z5vBLl#|e0O?p}PD-isy?*tFlOTgxCD&0dEPa1e;LIRpV1upwMh6t*EF7Wl_(wdep}Ls*Tx~Y zuS6=Y*X+dB)PYN%ef-tEI)v?cT`mR|t*{O`uU1o3)F;2;z?Wr9A6zQaS{A|5 z2;!$oT&J-S!uWHNAG#E}<&!3&1medxgl8CO-m6m`iHQs5YS)mTJj>h&m1m1&1{yVc zNQ+4qOMeuhFW@Rar$8kKXoICCtNo?r!`$1w1K(B(hKQ%-@%2;te8QxK@{ru)gE|NaXu!NF+b56^>;pb@_{Nx!k0~-5*mGbClpXX2g&* zR^;b)Kqz4o6BFBT#|u-6Hiqp!2hTk#C@&sBV%{`uvH}(Q^*c703QbsTskf39wB1)l z_d&|lOee5&8<~}_`sBGscL`yspk8xrr+T4J6B-SJs$HW<2`iPb>|D40m*!qmnot>3 zN!H_NZO24CN=Nu;lB?YXo^@{T@?B0$z~NIyu9Bc9UJFSb`$#&Ey!Ptpqm|QAyJaFr zs=iU%l^gx)$ja3gOup0E+6N2~z%iyds#R}hEGh_SgSzfD>7{1`%sy$UUoz~Oi_H7y zqdDPmqwSC^rDsN_{CUs$57NQN8euwJotWb|wPI7sXWXq6L{}$ve{m{qc3o{ z>1tPM#s7FPiEz9t;lbQcmw$p3d;=&qpIEz}fK)UgeSPZco%hx;nEY%#CI6eJ2!--wcDXN?wyi`$}(SwfvYz*4XMd9`%9hxrKW@k|;swy=Ay z_>AJQB)EAw3U86gRIh5?b!?gjCh^MDdsTY0Nj`>b6CPEY_V@vfR3;P)jUBr;R-3+* z>dFk-j3krT>^+N}bZ}KF;yuf0sr+M27>CTWGqCbPR+a(z8&KHO2O=qLjGUSHolE1; zjxZE?2NEkCkkP)(&c531l9Q9;4F1rdb0sk6Qd2#uYlE=JAlY(<`Ma-kQ+W+8^q@&d z1QB&#;GP!T7;V&uQUtK6`WUae}b+{Oog5?rCg=I=T?nb?#Bb#goA|8uu8T!6ck z908i#&vd`2k9qkI-e@iH8;)@wT$mvO6))(zvIpqh!QE9yBjiKe2I^F$|9+h3lq@aK zd7|a9=ay&$n?s59QhggXN(Jg6oNfZd!+>UB*gHDn-dQ3u(&*(`x20Yf`Z+&(boEZg z9&%1-j{En6^NF=G$DlmgT2VA!T%T+NT!747O?wB2LcOFTZtlKO-JV3krq`}~yyDe%p{}$`v`d%Q!v+z(z@t@2AQKd!tgHLyQL1{(G=b$ZK6n8*smtRi+D4)#{OKT z!&bv8npo>^jp!A9x;1T5=P*k+h*@m~_GCH=wPUrVimukW0w*RW^r2Uu9zTQ>NbO4S z5cUE`R4}=CMB=$SnwKbUe6@#Um$1ue4q`mcCKJ|}h;kThn%j3(K3;GhsrqE==$OE^ zz@B}WDHg=>fzApm**_2n#<*y*jxO`5eP{jUc1^N7s(h~8zH6&|J%qVkmkr4gi(w2# zaUt%%0hcro^wGSd`0*miaN4g))1F;>$-U%C`;zKaB=9Cz{C6)gg_Ppt&ei^$A+(gu zn{;8X)?nMX+l;5;rsH3+Ac!d3H*^7f+L=Y=x>@nloq%Oa2@mocT{KGlw1=~*VB zr`mCpwudF30%`|_NuDMq>T_74?j2ZS1opdqjz7WFmtD0K6IdX>V<_u619M2MzU}Gc{^HfwOfv5hEsTvV61u;pGN=<;Prz zrWDP)l+K)DdywV26yh>u*)!ZgK%+9~6mSN|_e+ql<=Nj`tKSX$L=j5m_a_L{t!=^~ zo?_~~IjAzoFOm7*4{i?%YwdNDl<@vx&Q;mHlJ`8t0Q5c)K&85X=b(p=3)%h1ZH3)z z9X$Su2e3b*#r9me0>pS;>ujWROt2fq35pZqIKc{61}Hiyw}Uy5VKuop!BGwhA zKzUR8H0q}KZh8?qt?OQiv67mt@sg=cX2VlrGPG5Wnn8w6gtVfunb6`4Z0*65JK43h z*uaxQS_+bN7M)f+68W7b8yA zLg*4K5By>nspERoe53m!Lxr>Bihp3Ynn=k$rbNZ)d$y9;yN+wJVeD-qdd?NO=|?uK zUfr&p-JG6OUZnip#u*Y%e@(9AR9K$(#0#Z+oaCdz9w8b-D!TqoEoP@@k>8!{(8RZSu>4q_= z-}s34ZODATKCJ8nc^%txd;ImrEu#bD)^L&`WDw|9-{{O_fY12$|Nk?p!b|)z;vmd; z@A5L0@lNK}31_Mu?ruTmyASW97aqFXtq$C0z9i7a`kPMFd<-WS%?pgZ_6g|KN z_I8^L(2OS4PSviHf$_s;$*N^O_^E@o`Pe9W0(N5M^`T3JR)srpWM3CNilbph)ANyh z9Z~5nf^AD))5$gqjxoufiH{?*czNElO%JBF30cjbk(rWeu>Tk?QM2ZkAO}0Yg&8t% zF+Jz|Z_B`l0c1eotwu$Vg|@c#SB>~c!Ao3xeEj3_cPL5I);F7+_~GB|Pe}e;_fauw zrSxouRs}@>?+}Xv^HJj-69`ErH*})G4!~p9A?T9@Tg4`O5-T(o^lW4;C$4iCWB>*6 zx850afskS&>6c$|jHWr`nOx&BHa4FBFtLQ98BSy1I=4>hx~#-thIF1tEATdlsOP zZ_l*)@4@Y1ro+Yvl@}&Ri~`JO;UG^D-$sdyk^L2&+Q+Oci|nUD_cWIHM1hGj>{q6p z6e$MS)$9rrwfB^y3URD2&p9S9?!HR?IW)R;LRo6hjuH`*?p*_2i^~Ps%Ug5nZ)U4j z7j@Z`*kWO3YwY(w>g@(B>g{$83Qj+C_HZ4L-`sI*C;d0}grq)wUe{JBNo{ zh09Ng?u91gz5L1CR$>kg4l1{PAW*GC?U-MIHE-3bLT42QzyY>C&m7LOo(55c#ot-= z{mue!71+F2-|){TdxrjwDa$%ICx-a8WDrp8W0EYT*H6_WsG#dq(wHgC7gUH^YW?|;Cb06?jX(GcR%Y3Bem224AcU|@uPn~8eZ zutofNq4pIRbNz=v*49R`udxaX_Prdawbz;@IL7vL&k)-}*D*_OA# zELp&fJ71gG*Ae&X>4u`QV1(6I^J^U^j6x39lUeO1WP>IpOx!js1>8PS!&00^{~4kE z-sQ0;9PUu1VwmSu|2gI|D$CjZob2!Jlmxqz44r}UyJqV%Y5Z%z*oVKN<)q!*wCB6o zV6^C~V)+mL5-mrB#xf?-q9tZzevU zK&aFp(XRW?mf{HHbo8H8GQLg3d~itURN*2xswU|ey0BVLtvVv8s4T6K)1yV%Sa?b8}=z4!$Jxo=lyMpqXmsUai z`Vaj3VhCw;``RJ&@~7|(ze`--C>kwfegP)9lxeio%V~PfgRIVN%-3u`4hPF4=EUY3 z(xhiLe$GdhSXr1K=t87#G84$zt=V|v+bS7&qh)m16K|B8I3$|Pq-B$96%Mkm$oGa= zTo+L4&YBhPNXBkI=HG5*p-WJ#b95o#=~tGWQH&CM5nIR}W#n(v^P))pajb7XzAj?5 zTgECdR5l*DH`lkDKxi(*6JENa-#6zELq<$?Y$8$}S@vG2AN^s+^bT*tc@hqbVajZ~ z`X4g!bh;2&fu?AzY-Nr(a!2jCvp}du z8PDsfY zfr^;$_ zDtua6P!-#xuKbZx&)wn7KO90bu1bQd!$jZxhBQWii-xrrv&%RlwtY2U}`@+&|bu2$XI`n4uEk zGEjbq%tQ{~_ayo@e|J?-rvTVeD2szC%)3>JonMqqEU^*uy*j0@# ze5;!w60E(nB3jW%6Jnmq-ZB;}9+?mP!L=wftYE}VFS?>JhM#;v`}6cqrpL$PYBVQa zO20&1s&)Nyht#*+qT+uGA4xVH<%1?{em*o7dwh1|A$n^x?W#_r&jOwWZEotazyq>Q z4&E5CO$PqL{H2 zEOK%v;-8Rnhx5O)^BE{-36ETAZFNm#EGC$dEawMf$8F@!aBoyQh(SVa1*^Q&(=>!> z8}okg)t-2<_p8MZd^K}56_iWdtkfx*7|yTB7oYpKk$dUV>Nx&ffOtpTC4~u^MK$y4~bKF~n^1?XbEl!N-v{*iFvjVK&|)8guPSf7g>=YbGbZCJw|( zVh?`D{?K3e=2nq;i9Y<1Xh;TJ14#v@$^Q<`3vg%>7<^{;h#FPtYF}k0p8K<1#%~PjcE2=#P8Y^4y z?7oHK$|j_28I7WlwGQZsZJ}<91=$wH8GD>bSr~qss+C_UlSy_kPM(Hh7tYeYBpsTX zksV3CJU1?MC~*vKHRA0v$}yK>sDY?Tdvns>REF*0zmA`J=OF$4a=P-hLi_=Fx2k!= zT>OHa2~%46{usKvcu<*^u+X@-X`kD+@CBjoQXd+!Jt;QA+fV9zDa7E8%d{N$UZCkt zKge@%snWi4I*^-`nb0fHCfEYUzw5MizGe(S7_Y zn8z_SSZVwDuGHuHYAT=j$vN{a{?{Q=hQ&Uh+qG1=Pj2GdP3Tr2(vX!R3Z<3kj$w#Io7jbj5yU#;)Pa3yL49VxAQ~lO_gC=F)~MWqg{Mn35>{I?x>-3 zT59h(8GL`AwoKdo4~8K9ccKMFKy@Q$>?bP1Rr*@@ftfB8vn<*xJS$1)Qe0rtOFf{hSQJ61KW;M@iRiMM0@U&3&wmcOT+RV zBm~A5ss^Z(CtSlJL|p;>c53(wk@MZ^b{wwrHuq!r`mS{4>IDCPfZZROu3l1)UQ-O~_`CGttsRcbna1+7m@ z9=dMWZY`jJ_)tDPK5w;lkLmB!riTc+fS~5>0F@ zZl;P+7-?LN+a!J2X?9imA|yn0qlczth6;6Cv@)_IASRt?dayf-)4nXFa)Ap1-G zudH935jyc^1k&Cy2a~fTpXB)u-zS$O&nL|>)mRjn(L}R(5UGF6;uBr`1w|fVJC82S zh{mbSK!mQZv_R1_r=K}9|Is-GT~qvEg)e^J%K1;B-Kr=GQkkUB44<%cJJ!U9JaMEl zTUjO6`i%!nx~sM5ZMoLvx5imS%Mfn^!*0UT5tUGkh#$_gH86}3o7;6`Z~dV@`l2Pw zyg6V^!WdHs_COgt;8*y>|3;xQ-M|>Zb)y(fVlfDni90h#u|cU8twIUbT%#A=Y^Rd) zxDX53-7*ft?%vTk0L6G_R``EJr)?DIt^u;(%+$5U0!U+PFeefUdlF8V#*%1ZM>3 zWDX$r3=(Y3odoA1FRH-3guPv}*(%jjr*R6a>k5ju)eXDm?o}h>>8sMQ6(*k@iCs?H zaejA~KW!qLZq8s($`Dh*=}~G|-7Whmg^KM`Yj5DO@^Q8+3Ga4%qKqSh0gN5t6gVlv*7L9)8BLCkaJ&hnwizEgI z3v0dF{``rS0}L8f&igv}cuP;Tg74pZfNQ}TXx-Y6uGnEH&&I02|9?}&z6IuwVcvGr zDs&0JHDyJ9Z5m9EZFcTJ7s@TFq+{t)uGBdO9InROmIjot&cwFV*}K;m2J>XGwHA8BYTepMjVAqjlXeVCEaXtX|XRv z2pi=5B$MMuXT@R&Jv*t-D8{yt#}pzz9WeSd&*4=d_%2-5oG8MLFCydnP92ZkzNo+J zu8%eMXPW@1sey%^Q_zAUHhQi2;+( zI1&naQ?ISkwdp`$EqGOxb8G8dpUxvHPk*7EB{-$@oAQUw?_5+f1lWr5$#9pr<($`1 zbIFf?Z$%&jSa?Fu$U4|i;a7qGe|vk|dupc}s2BAi;=viQ%GSXJ0?x;zr7f2l7_#b$ zicl`WdUNCB-be0R{O=Z)T((kCS=pz+TuDVY&-Kkagf%;OyZQfUc~vdw#4B_ z_QMUV+z6LM@@m)`Pa|L)?~#={ta41%*Yec5WKhG)8A?saaZ0(cUy)&Mzfm31u}^z= z1|XdADM#F>_rmhb&zq*gD~oyxN}K%4q!rZNf|Kg_7pZnn-Dk%aS3+98!yOO#$!8T_ zz5FtOo7z59;WF_3zX6>w2_d1&*cT~!XJeYOK}o4BrZZR4ggYuZE16B1H@4(VV|`4} zu;{E}eDm-5dEX3HgfL%kCqf*}B%I==Mj5(Q3l}00`;EuZtI#F&CS zV8&+w&sKy5f)1G++k#LOfGG-Z>{SrL09I&(iJHoY4|U3FZe>Eq%+Yh)@57@3g%HC2 zCVVA;xg>95R0>W?$?Q7-!AA_EFmUMBbvf9)->j&EK^!s_mCq~W-|=V!ozu1BGo*y5 ztIoKKy%aPjZTapd42x>gRse^zBIUH<4h*q|eTB2fGf9HmuP!qEqrMfJtLW`j@>`$z z?#Zx#LPNc0N`l8st1bWc{Md$rx&k2RjlgA)YpNOr|BA}1b@&UvSzXuflgwYI$!jat zT`pt&Y|}RYfc6HiWjuXbpp*RC7^hhE^gP7JS81fJmo;U0uct;IhDf85?yipdxLZ$N zJzzyCxUl~E4#!MLEsTDFCcfil5h+)n{=LpxIIQ3Ku+XiS%C(* z)j#4#yG>?2p%Q+4?@D3glaQsrIu}FU5 zdEDsQ>W)J#G)+6?TY{AI7k7aBL;wzv2#{31R#aTd_M3O*Zuv^4v2HpK(=fHDhz>&* z51@-+|6l`IVWlK>8=x?4fRgUpX0%G08JILNuq+6kz_$sAy$(VSyaXRfXcWxti+fwb z-#DvmVp~R@Z67{LWsJk0i=#WYk^ATphOZaK*!UN|xY244`9$#e)q%b&(M+6(obkIz z4{oS`M1F`jq{QHd>syeOKi4L!sbyYgs5t`Tt+OTnl`Mn~y;3Y>J@ppyiz zZ$9bk>VXA{1?06n4+8qIu8McaPupY*x;UxxaJ_5`S}p9IcNp={TCqsv!RU{ZtxFggqro|F+b`mT*Ow1HF2atwY=^ zO3Z^PI4r|Svu*oJ`0{TQ=8}$ehwr4j_NZW*+nUg#^q8mGZkC77tqVV>vzxpiYPaeg zzM1XNRO~XnMitP~8SD(Pidi2rtMqJfWU)`V1u$p~B z+ngkchE-elUt#+4w=f-8$ij0H!gzh+B+;{7gPq5HJs>Z3%%FyRb#J^OL|G{50@_9Q zJj*6}@C!KibFHo5us z4UDu0a!8W5`&>Bt#Rte>M+B-bk^UL}XL-56#;zdNdBx!$DV}i6?2E@^=k44>T@^S& za&AS7 zIXZ=$3`pyTTQj1NqtDay;9*Hd?g);4hoHy7ilyj10&1;@$V&%(f4lpAIyy6zlN@ z6J#a-+iY@An+?Q_&GJ{cvhvzE_3;Gf=w@cHo?D!{GQ9ElW*iY;!llBCW3xuwh3T-XJWrs67dM%BJdk-7 zIrOWvBoK*mbaXq=^y=PN@%V^GbRTbYu~uJHrLzdSs|3Fy(frsq1B0wJFdvr$3#3v2 z)(^%&b+U}#$QT%TBTvq!d6~5{KDB)y;4`ilIhX2JL%!6C7^^aDti1W%{#hFqCDvJZ z;b?axce5x%6vw>F?e-bR{9Ht-9{0*AMge2em&osnA@m>1`rgizrtE`~R{6`G|1Z&* zX!*oN7wXOZ_yJRBd;^jbGcz-vgV&e7O1?^Hj02G;0-h(Kx_ZFRi2A&$vC);LQc zw0W`KCYyD6;QU#!9*EGd4F{r)O;a*H-EC-t*Z4u_V&j^^?W)gSm?T~-g` z&ZFroPPS0mPL7(g4Frb2>JA^LJs^_`;n_LoTcvZ#>z0m(Rabkv2;qZ+% z2cmxIQsam%(H`p`kP_pcVXB9904)T7x$0Zu+{YZw`f`U2Zk@+O!W@@PFt?DXb&c&e zEn^UMIyB;nKQi=rBzPhs(QkEZ9EUkMk!Z-@^#^`6_4{{SB7pJ}s$Blr$|?}@{&21; zu#KkgP31<)Gc1$hfA8EF7px;Wdl+2uT_>z@KU@%CEjvZZ)_HE8AvV1O*&`e1z=CMD$ z<)rpT3zxqUL0-5xY?fH_FDH|qT8_?2d(uVqR`J|PT%!j>m>fMB;&7B-_n>jD!){x7 z9#>wlHhWS<#0X~1zaaQz@w0h6LY~nfYexL}AHvA05Y`6IK)bv9b&f^^6vxcK8gl+` zD~9;jI_LI;*%fl^@&X-$(mG1Xl~R*!doyPa2!pf~d`r1F49bW}@R2KvE53cmf`*G7 z$*yC#dIr^Yp|}SO&C9q45_Gpla0lcul=%yPmC5b)V0ftvf|f2!q9V~~Y-+MO-&PO+ z$!>X$xwuE4mz(DxiXS(8KtoA@iR48BcIBfW(;$7$3>leG7+Q=19c$(&3+yQD#5;1L z;DT6!mnk2Btc{rHvH75Y{b7Hc~ICo)AVAl`+eB#PTIMkKH<@m`ZE! z)uN?XllV>A0F9#)g4EzvMv>#I-(}4No1FBkC$nJ{v%$=}>nF&^*TU|9woLa0Ulkey zG)6PQqFZo?yNaPxrk>ht-7q!$5)Cvqe<2srmA^zxZsN}Q<>fkfI=Bbe%Y5F`_yeOO z+>;pwBG;%DW5-GOFb--XUPK3`CaVxVDy|$?1Xx=tr>0e56hUhX<7<@=zJE*jz1f|Y~#W1N)9XCe+A{~iP>P3 zhkL+db7X*cL$)7@rj=(PW4Scu&O>16ij9(eHcZ^;)fO@nP=~tBA1YD5GF=gCe(X%o zV%||xplOfsak$0ztuZHiggYi%VV;SN^Va^|&koFUZuz!wV!p3;xD&L6t4>TUueez| zCpjgvQ_q#Ag`(x&<^Nl@^nc5i;~6SJVYUip;PLM zV`ffC@L7ib#hV+l<94IcQ2Kek>H7AYUPR$*378BEyo`^Ec0-@9Ns0;UElP>Zi$-+` z0DRuu{4nJ>x%QrUszp9K=B@sgdY*S3;Tta}zrqh@2?bJCcyzduW|M6ux}WkMHqR8( zqx#;DQag((%na}6c8pzOFmE($gdGx^8XpYukkgr4kA?8t{78AFHq4hahYP?@zpTS| ze|wQUKhTQ+{#U02P6lQuRFtnRl3gQg;HY?_ikS+EijVrOjp$@6Eh%gh`L-1zE_A`+AD5@_Jw7-h;49=cqbxT z1D=udW(UFSycs>KOzELKRqTE*$(dj(9o&4b+$h^3!%xokBZvBhv&A=CsOZZjJSjc6 zY&w#BwHsSQ#p$xs=X)k|;S-~$h%@#?fwiRu!?7!+_rlLe>YW9A;bA&kOEFA^&zQa; z3;X#Tiiv%Ib@sSt9oRI)G{zb%#xdl|CfLJX>YR_Ox+YFa-Orvtg-eX^EO?+v99*0ab!hVuxu0+d%(ZkCdNDO2fae=QJzv@W2N{!sixry%cjhD|Q$` zePr;+)vNm_I1`=cR>4It;oQ`U*@nLrBDA6`u=-8J)`VJSAYH#YRvq?RP^ohizYi#_YK4f!7b2w)odNfAt4d^3a1>S2!8MR_k=YL}C1B8{3~&HwYoxV!aM;NQ7r%;Q7f;lWfGc&VaF zJ5_=AgGO#8`t-nfu#U$o^hJHBLcC#c>`qwkf;feS>}1C~8KeX|Bo=Kg#a_51Hl{6l zg^Zb-;D*SiMdQh?n8I~pIriP?0Ab6tI*8G326WyxKuq)KfCCnZ+&ex^z03bzmikzp zDVzS<77jZ$g1J#~R0$}CS~YK)ywE88URZ2f3VI{wc{_2oMJ|sjeKzOD**uMH*HsBD zYLr$GOh#UVhG6>8*`(S>_(@9S$Um@UwSsr+C`!o}1IqZz*(;lgn{ zpkkj(sB{-3s?+z6RJ8g>L5!9BBNYkD00)6nh7)%NP2sBW(l$rPm;+Tbh?9=;TV=vT z=!5-T1gxUjEao-Dn*%M(9?r(~;COc8_@hv`y{Rkt1+8dK$}mfkkU?<5bH12RUU}}R z9zV|kRT0RUXmg~hjqzl?AoZ9cN?~r@Em}Q81B;wX9~qz&vlXSj z3w=ljZDZs_+=G6`;tMSulRlFKUhAv3@sf$&YB>hOYTcoB>b`Od6UWcKfG@>$)C1;5 z(~`3Q$v<-Cayd(D{zF|?ErT$abj&>heBKEP1@J5Y~p#ocm`k4VUu zO@&f^KsrHd^j)dA{`gI%0>$V=<}ddm_4iyc(Sch0M7_Vr|3|%3llNj$z_%2nP>@2U zL+CG45Lte>w&!^F`O4hnZBrMn#BWn`(rJ4(+Om%{x@V@p&0U!evd>#=r6h7|MvKc9 zk*SST%gTj(5qrV<@_lnGhYh(78zMVbVhN6^ze*us2ox1(Dc36vBx%e16vS(mjXZ`v zdzuq_`0(l4Ltjf|0rXfLx#w6{TutM3^m(wxd&{o$&(`aFA@OHY)R*IhxJves6NxyV zyQO9VKU=wnBCj%6>1^KN?ptN5@wQ)Cgv81Gxt#o&XF0$q^QUzbqS~0`d0_2I6C0Ur zx|=9Y;+7c{*I|k(Pvk)?PwWyQrj&|#OrE%t?jv7v3tyTuF-jIvfU)=7kVGl|6A7;{ zx%R(GZ5#8i1PwgV)K4WS2Fnl;JwRu=8UyvYB19@UhcIWaHb*gZuTDm~$e})cP)c!& zU5szNmeFh_dY2I_-9}wP;Sa@hMgL(WqRI*JUyYp}3K+(`{Tj*Z43>nwxrZO=cEJ(x z|3Ljk)dmA+O_8uicCbFDQnj9A{q(I>p5>T^&l__VpFTOr$$lZvvgOAYaA@>psTO?+ zGd$%vDF&0!FQPw$O#}{+p&Ar9c*%Etec|l1C&K5;tyGSbTp(4}hL6Rrnsk1ISH+zH zP%QV{n#KFhm9p=4xaJIE{BZLT<9P0HI);oRrUD^|R=g^crd#ah!Xm22Ff-7e za$zE*1O~&nO|zm>tIg1m;i@p(oYCyWt)L+%lyGxM0j9{<%X=pJiJY){vDsb^{i$H!p4TeH9fp6^kgDMn)@r~0;KWr%udqci58cMnKtSf$l zxlvo0G?Q`rbxTda>bgvjMUTnh^C$rY*BC9vf46{6g|*l*_@Zt?Z_7~npxzc>yD3-jbLy|LBQw8TaCmwAQg7}m7*oPj*{r(Q{f1TVx%}a0^DnL$oA1M;9byNf zcl|V^z^eA2=*I8Uma;bnmL_CE9&eD4kfb3@riT3T z$nj>e!`s)f+DB5a^(E(RkFn*TmB7A#PD`=*SgNaeclg1=#6d?Vdcq9SVJ zW!za&T!`YN3(R^+I}@xPk@(wr=R8&D67)_vo64b%N=xDtMI4I+tflMd+Ml#~c9@tL zCbOj}dzLg0*mjNvlx_0D*^L)94_K+*DUFDvFWytNTbg|OAY{W90^ruQ_a>dgs%}2A zq5Jht6)(8Q@~(v?4&X6+%79jgTO;c+gU!c)I{x@oa0me<9c;-xqYfW(IGAc zrP+7fMD4|&X4`dzB5UYwR<(cm2z#yhVYAM=#E9`Xjf-Xzk&GGQDNP<}*%DZ4+rQ|M zieJ{_*j9cCG-bX;hf4o$0$8wap%Ue>C=AiRi4ebpp{jrQU`$52DT1L;nVsF0<2#nf z`U3c{nQ(*!DtH=l(6~4_R?{DM(uZ$VbzCT)^ufEkyJ2HMd5u?LxISz zfL)hHL6naHUtZZcameE-lbx!oSpKW;m9tttczxm3pD|-OEupCh^;XHEIDxMrtUJ|6 z9vWmTh8*Mi%FcidN$~{zMp;I9RGdwo*APKmszNB!%$E{9?f!2Ks(ObZjA8}$jku%y zul#TiUV^&F-KUc?H|ki;#wajoj+#vrT-qG4Rqx&#O)JO_jG-Z_PNjcOxst?RrD9W4 z6EM9X$DA_KE85&FM2QyLwxdeHUbeOAjYv|xzk?tBy9i70{Fb2EA2?Krxegg_O<`5 zWGI&dL5%temEZ?5+MWZ=ZXRKCWer%qDau~$VIhNE7dCAm-R)|j4Lsk#WFBA~N0-X$ zi;07NHm8m0fakDdpgk1LtE04~NI2Q!FA=|!0i1>@ctIO$em2dMm|aoG!JIGRRp+dy z1o#hiH@n>%edR%U-a*W6ep^U2;+&wh+awOUGI2)mR!hyLT zkk*n7SU=qL+b_BZ=KVeNMo&`|pqdC^<&sed^|3GGQA8V9`U9CIU#s&P;;9@b{5pFT zJ<|f*N&*k(Q)1rt#cj9r4BCy;5G|=YkSYBIn3Yz`{@j*<904tRN5^##+SUi`+%o66 z3{Njemjj1BgKn#qQs)?)RzjrYszC^=VOkIq0}T{w;aLCIQjv}0k@JsYukh=v@;s!& z#bPcQYiRMtDbakWq7}7TZ_xX!Hf~2M5{D%odUpu(iX(%*n#%-*W%H!=;KhBK>=|HN z#L&0kIoq$Cs=jG)fG-gfo{EHrJ9Ycwr#jgv&8c>PFSmm}*rMqzz<|3#g1p=2$mb(THUG4aa&Euy`w?2K= z0Oj_&XiObLNOP;ygF=(S;h)07y5gUw;3h!zxO;6yk5u59&F#>ajt<{7%0qPb&zmZX zRqLZ?Y0)_zLpZBPUVrX-mA431u3< z{fynGXAjZy!}DR4i&AFTXd@zaD1qEquls|fSSO?4MVuOja{RUsGqtwK$#ep6ZRXsf zC*tkp6HGryl0;T6=R*oLdLd*wu8G7ta(2Wv*vv^Im1LOglwY*6m}*9iO9ejQ90~k# z@>!|vJxLD0P2<5A=kJk*{SAaluXI7@cvPB^8I#Dbov2etyM}WVuX9dLNpszkxJ!iW zm|5(?tbwm1&aTuBT&+S=^J=yIJ!2h0_%p+aRm4>|Ds^c@&RdcHI{qi=7k)dMXG z9U$c|{X36iRXcUndp5N7@{@n!?alvB>p>+8N|6m>ynMR*^EQEF^Zvj{8sRsaovXhB zE7+W9Yro&nc$!>@_c}!a5|C%9@qE?b?zv z$4`q|Y|6VM{`!auvw{s(a+O-#;QF<>YV9R;yEuH+J=bSVv%b_bqWY2m14nFojBw(i zrar?(YC?pI%(goUfM~o3F52HK%75W3oK2TaTQM1!bXL}tl3SNqWJ%;sS+$zuoh0*T zw6lxzkbR_ieR;;u`TH7UGays={FcO0w3K;CoER5^__0@@>$DYr^m(O`$x)d`B*DKT zBSs`8j-4e%C!`Me%{#(X#egXz$39NB#w^cMPIuzOR?eBr8}GLgDO4=4^QiKh zJd&%A9L3hhFEl2TM%s^j6ulI+T4V>g&6Qm#J=A+;o+kuJ@lPpGpME(pKp(6TB3myH zY9~X5qtH%a-e5|z#jcw?5KY8HQ+w&sEvq#gdS8{uHd+zrTd|0N#mxLW#{MMo2Z7w` z_jn#p2Zn$xd^H1a?aCA%BXg6VCz}p(T6|prc*`e9oQB#yi1CIK16{`VaTNGO5U*KU z`_VW+nM*Q0;EQ_E}j0MZ-fwu#vF3(L-q4wNQ zH`q02Tuzxk*s90oJ6f$-?n3Bj@kt@&V%EyNm}HwhL6g5Y7TDy5_>yMoYGoPO7pShD z-@tV2iSPWV%if=tEl*H6hU1(02%O0OBVYm4{^SGGWOOUvm^Q~XI{AD<8ja-V$H|cU z{>mcMvYQd9jO2XAV-;S7X;B6Y{BIr zdNYR5fbv4}UG_629v9~I3L~RpG-eOSE}bmKAzX)@LZc#{JwGXqkENnDX?r@Rch?9K z@9jKvq5fRG!7NJ;uCmniO{etcSfLYh$}fii6#7nkIdu6!u*`yUl=l{^g*QSNw@D}#))E3ZFSJg(;jg{rh>%TLqU zQ$pZNM*(7#!J(mWQ(9kR5b8ked96>b#iUg~KHX4KTs-7V1N=h<6TJ%1w(4Pc4n=(Y zBhWdp#s&PJwOU1iZt9nW?lg}^C{O%XX3xSSD}e1njC;sJ43QEq1(SFBDP@#CN>xrP z##V2-)2_trc|gdR!bMQ_)WvSead`+h3fDbkMiRDFgZ<+~AkzFWMujFjbT(Pay8(*L z3?|>DBNNXGs;)V%%J+#MKa=__m1y6zTxIcyR7AJ2d4nFs=Xzjcdz&UyFCZ%#6xYhDF!q!9qCv4UX3dPW|m}v8|+&$V4W~lpdv>b##Zqb>mx%uewvG$v#GDhddzDhT6cnfi=Ps)<3S^ zTY4MzvCtTKv8o?|gk7Of-^2olcg$(>jm6PZakmA-0qIquG;n_Ok?|+1~BZLfGE^; zkUGnDK?|}9{-A;2Dse9_Veph6WAo*_x$~cgD_Q?s_;|9POq#VX3Aime!~~gc$|=mK z@L^r9=w%_hp+ab+bCrdSCg z2gk=&TcJoBPCJKHNb_dXN$)mOZC+~~$t&3$D%Fg+ACRM~)1t+e^xY%sSMT}J_r6s83ipX({4JRD z#)(Rwy0%p2Z0@w+mAxjW8}OgVzyXJ8PSEPpiGl&hX@`+_=RMzJwB z%JGq!J?P%JN}*{Lf10rs??+fkwWb&+x>-Lr20h;dKEaQabWQPmvwU%OD${xLogcl; zR9KX>R9pi=l9D}g-{#fMqN7teY9#ZFhc4ggKbWnG1_&rXHEWu6mEyy>s*$UA5329u z)YU!bX8SogFic~^&E5M3eKYYJH(KNjM;{yWUXs0K9h~D#MzxDO;n0v(FBi(faCMl{ z!DsfpL4jGE3U)D-)0^dkkJ|d_%m-l(|0SI~Wo1}C(Z~}2rNjuF_5`1K=7e%q8+j}w z`AWJWUty;DrQ=C!NEHvr`5PIcQR)voq&!MkJhzcKEf z;}z=lpL5+pLkn6W7Dh`l{ExG+a4H{8h?RmyF9BOy8?2M^@CAxU=1$1B_nrKd*4DE< zl{Ecw17Vnc+!{XW#YeT+;Z>9m>(53_`tRFCCnn%SRl@r?`u1bt z%@870h$P70OzQKaAy;5i)FlKe>zH-s52FO9?o8PZPd9F%(~}F-q;fj$ud=U*DHXzB z^oGD&vy;;^Be|ASq+wzZi8;%Jgo#;mkdgQF#9o_{pp(t@o?Bq(4}?*paZ?JoNbJkt z2rx#mb8`9S%fuvHMuncq>?!q%JN&5(MTx~97eQ2~Rl%FSY`H5NLcpDn>^KKE)ghWgctwg*%34~X zSV>95&ufuu7^vp@%cvQptg-PV&*Yi@r!To_=!WHI6_Y>I)(aqCmb%UlrXAlEE|Ood zll5p$wwlEoLgtaS1wg8pN4|sTzt95KCoNBu9^NKg_42Zg!0mQ6Kt7JHHlFlzE|TXt z^}Z&CpoagaulPdRi}|QMc!(thn?9Y!VYw2P5?j6YX0RYP9WCy)*t+_990I!jd|kaq zsM@B!;9%uVSb@=Pd19@^(%@TpJf>>URp$mxNAIq9*gi8DC3ld@_RG#Pz4;j&Q=c9n ziEg3J*N0?PLv5DQy_NZ%%(QBuDbL9&|91VS16PEXhj4%x&{mjb#cB*~ZNop_e2^Q? zqpx=h;V=PFVJFK&$*!)y)`Eh%&+RQPZET)JzG8FBhZ(sj%c@ypw67yt{|!vM1ec$A zHjokH>{zmm5Q+qmR>Mv+^>=G+20n6Z233DXBi+2-Acok>gv$LAW~17izc*z6G!Gw( zp31|Lhq`bmJp>@vAj+n!Q4uReT!|8TudYkm583- zY%zf~7^@~y2I`yTzl=Lxk-s3?=DSRH)2Q3HQ*@uo%F4;+N=lVMrSHDRa_0vr!ohDb z3~h<8Inp!S%P=c!zy3e6zOtdJt!rD620^;JyE{Zex;EY2u?guC>F!O3^rk@?q&uah zTe_vgcX`gapD*uUSaZ!e#<<26818;=D;zv+yCl^@eF!Y*7}hDxIps!Cp9~MoBb|nc z$<%_A9M?q&5BZ;!W>_1Tk}&9Id{xza@5GO(Xtxq?muDGHtg@$zKg_q9_u<$XgdRMx zTFP_&#IK}=7rrD;D;*U??;qu)(v(*}`Q&$zyQPK)K^ z`;0}UAj%eN(bfPW{HfV7pg<)un!Lf3-UJs2DSfn7!5CES*E=Rb}o}1A(Sa%I+qDl52&E@uOv1a!zeEdp8p=^UlUHMK;n;L9oCwUn2N=UV$ht{vXKkR z$1|gzRt=Vh4yQ$m3RkB`N9ZQsnj(iK#5<3Xy7%B-Wtf{60{u*j715i_WS_m&?{H&PRvs(3DLXMR%t4H@ z9g9Hr%srQRrjr*?=*;5gpOdLP5VN$u(q<;}*eRJS(2j=Z- zX{G^A96CNCAG)V{)ZQEFdZar#uf(F*6f zUrvW_MNW9bNH9=U@{WJsQf;77DQt4Gs;2njOICauTrF)}$X^mbr^z8~UbSHUBZlC_ z1Sd4kB9vaI$f34UXMjy|01*)%N*?M@9unBe8RrW`uclHqbH70Z zfv(@cZv7a709=$fu>m|N(h2VGZqbl3WE zl4;Y)$ouv^k<_wuX+ZEJ6}L&`4;|s5))L>UrF{T$nia-LA|&0{ebRLDmM=-XV~UtJ~i+7p+mX&GDlaxGQucxKE~ zs`)r9gLVWZ#TL=YqYWv=4g#j=Z6+n4dc_A`Dq87EHnhcIhnBU{0|kskGf}nymdvv` zS_|)=7lcX(`MepnQbIrQ93+hLiQZJb%SU@LraAlbRQom9W*QLE*SbG&Cb!wDZdK$j zx+BHZYgZ>e2Bn0un8{9AwiQ}tx+Cl{X#N^`kLiruLK0-)d3q=B8Fa7_CKO9xFJF$k zdDxP=eQJ@({;d!`)C|lP7UM`95H$YNFiJ`PM;8L9i~rJv@`1hghGXO_n<77e zBy$l9o9 zQW#PzTm{7VydoO0`MjWB3<>R9yx_SO>K`q!z6ffl@KqrFgkDvBP0={m(vrn)}5 z$&|f>Y6&q4)1~p4w`=kR{l6owY&_=mWJCg8NDMR#q z>Yws?Cek8BD8D2uho{j`#nK`tCd84VV~#zd)7=$_R}h^94Nl=$_lec4W+kki1_$vF ze}A!^9c#k`Ao*xu@z;A&IYe;bOu1j-hCun6_)IY5kLQ_{r7%88VM{Vf6KnfxJ;-Y8 zu13`6w%cA$JdqzYp3J_$f52eJ|GXUlz2yJA9iG}NDamDL3nf7}S>^_E#V2wPj?DB2 z?WXx$`rseoGDX-72R8;ED4@yWMbeZE44}xFrfdqG{+t_;c{RWhLRLE8vtP<^x?duC zDJAjE$97>7_N^jW`G!7cQ7yFUAk(55#BChV5vWf-VvU7!rnokz5=93$kKe11E;g65 z?()Jcy6RWE`3`GU&1QhXXW7^hB@mP)o2iFhLvV9DKp#=Ry+()hpUld%YA%qE* ztI7NHs>yZe7^E>n0$KhnraMl^?s7W{QWm;LO2Mg;^n_ChNk_;bQu;UCKjQ) znhr8*?-NzyoMgC#g-F1@%(&v>30)O6t)(*w%xEQrA9eIZf6Ro)mr? z4-rlD7Zv=UN3!u>HJ&=4hM62`UQp|HSt*V5mclW++_~X$8j@_erlDd$NIxaP2DWsc z(Wftj(&QeM<~hx}P^Dy=Qf|g)_0Lf85)an1EWdw&L@x3(!nCJo#^rXectOuJx z*dvwd&R(Rwex|Q_93-Vp)T`63!bjViqaGDU_*eUNBE?qrHQJxpmoMs7ga#JHdL%VF ze!jChk>hpJ*0ku2aXo1cNWnrG!9VfF0CiVhjYr~B!Q>%^&=v`%i;^fS>e(y}W1pxW zUaO4oQcK>WwQtUk6aeO8iSOt0Bw}1Iu?YF<(?v&KM z%OE8+j;uas@a3>o{$3X$E|+0isahweI)EBSxUc?!#4_$$ zaHe&=>u|-KfSZ@j0hNH8lsD(U*pCYHzu$h$${;v$VnPY93rshfDK9Tq)zIMi#S2Ke z07Kv6zna+IIGD~DU{m_BL5g6Gmgh}>_aZ<@A!MIQNkn!G{XN7RnJ|G_BKyc{C0SJH z|45H7umbX64y)#qR#pV89{FfT+IQZCjGS)2DJJgj(qWK($CZ#~dTt)EPnr0r6Pah~ z4CUBMu$u1Qo0Yt8rDoA2o2ZpVXFEZnJAZAb6*)Bl(1644c*(bR=KImi>Rsm)gzkL$ zrAR{i@n86RO1m*sBhx8yrKQ*jzj6-je?$(WJ>CdHQ0E{s(*C1UkyeYnn^PCHgfQVz zvnkr+-Py4MT*GyNBbR@xtqROvX%gUWxQL~2NO#2eyoJ}<#TIZc-^$;50af-x26zcV zd%Sf(lmDOY%gp6gHJ&g91Nr@%3Osr@hR4GNTZA%l?gOGqz$yCECF;mG#>qlSgUExVWQP4+yS#L03$rqLe$lXg zQ5kJd5#k}Hv(AKI>Tc9i)(th>buD_4yc+D9eZ)2(y3Y~Bup(rRaW8EcXKmW-NI~)@(2amraW}aw@{Xq_uR!X%y*?hQsucpn=iv@6)g=pOzo;55m z`Me)pn*?i3swT2TD0k!1L<&S0!-(x<^%}#_dc>Y(Ex(TGeue)E%iHp_f1xx3VA+(Z zL625k{Yx6mn2gZV;z^pSy$8w}<=I|6qb_-!Hh*zn8{CW<^o$rbl|7+c5d~xA=wBda zDE>f0+T^tDcMa~`W--zEC^S$NDb+=3j8TKAkM~+$Tes)33}JX^2=Q+WRyz=u_BRmW z9dgKdCg5g#cMIe=7+rID_hLd8f(JX&rMnV2EI!en>j))H)bJJoAV~w@h#Kt<=1PXk zV&qK_r#;CmXQ2d97bV+@7WvIQR2Evk^=puGYiMAgGd){!HGiVdct_93s!>edBk630 zm+GKzfdX%_twADo$xWLzXaSR}kng$1NV-vbG*`<6fBLIA>!SJ?HH%BCyKFY)J%7%? zZCtUl3w=qIJ*xV~a1okt?NDHwZgFg3!nh!hCkAv)iJHxwf|nB&!H%{y{Dfw?;rOS3 z&#eV?F{^mi!EBecosGyVS#4ew#Z=A-vP7w3h5^; zQXBu|?v+uUrJeW0R^?=-MSK=d+2}>p5z9pC*D`jce8-x-#Alz#)NPkpt5bdHJFcapAjQ{DOHi@ zve9vSZE>M#AO>X!OTT03k*2oz8ZqSTS(=moeOXVUE^&mrh(n7t@1!k)kz%-vc}nfG zop|UCaf<*x&UArsDMndPQ8Td#ySfWMoX(J2JCU1HPP=-dr$!rD1M1#X?J?9e-}wW{ zan0Z-6ZGIx%~eH|yZ0n=+eS)1L=~T4>iw(BCgDyh?3~zXd~I1@$@MFtUsJhny)u=) zCHH?ohXynWPNzB~SnOSs|tF`jnw*Kc1w95pl-TX%X1!ddOvRZ)5-H}{ps!KVrDad)Pz?goR%6^#r`F+4_)Qev zuNG6Q)&`faWJj-y{dX$^e7smb$c-dXGp!#zy?QVDM2s`w=j8gBshxVY%|yy$B4oI< zNh0`hq(Y~sZp=O0fF$bkKj(wb2Lq|ek_g`2*dRCbyVd~AA(no&S)4f9+H#r~kw*Ws z{`hOD@p6v-=Uqxl3ct$^qCdcFDX6R*Z}-3JCEH5MeJZ2@ba38_1l1v*Y0RoZCU!dM zq;w;xcZUQplPly21j&j{GRtUmySb>{l1KEN_!+6CH)&F?Y#vYZVjBCUX^Jv&m$Ocm z%cg0q0v26&Xq{Oow%vs3LX+?*kc_C=WGx9BYBtMcdPW&1$Vn4Y=a?Og!|!hLWWP0S z3Ja86Evmq;|4bcdoIq7V$24wqQ^dKGX?v5aH}Gj^V^+Ic@zu{ovv87?!2LCkc*1=i zNsEbrN|Ic?CT9|X(7aE-Di&zp3Q6-4UaB^bqBM|8acA60C&boSFx?Hz2905*59DN1 ziLzmQEjmkim-Fz#2_C*fgl~14e-3hCer!Upr=NpMXs#F7v zg**Hn&u4O9uz|3wo`C1-KR7^!Fi)hsV!+L!mGje`vxGJPu;T*adQw6nqPIHfg?@*B zjT=N?F5>ihF1^K;ZwLP#-2mK7@C3D6dU7&{Zihw698;C^QinzXC&``}fkvt~AQT;c z&t|8Z5q#Euz07vh1S4;apcNyxOpEv0Cw4`!qt&P!Vv%KYL#rwb{`)HK1s>Mn#(IUE zd!{oxV)mnGI+uk>&9})+OlkmGQ2ar++HIGA7IOzK0<&;dl&!7?g^2HtUGU~rEC|e5 zmSr8Nqd2D!F|A@L-Oc$-2X81B-DtHuK#{z<6(p4J?p?4Q7V4Du9Ok8#c}j2w?{k>v zA09a$Z}8{sxs28_476$OWaJVAmNRTs8O5v$&(dT8t^d-fO7c&V9vOwi!+rrg zwwd#3J75e*!+2Boc6rgXed@Gw{J-o=$!^~SCmm|T1gItieL@F%|RCv-I# zHv4a1><~aoQ)RLDJdhez19=}ZL9Kj3GBuL zcD~CN@Ha^aP^L8m@48_$a;+f3K%!eP>K*+J85oKn$=`*Piqd6>7#NHAqkh~tR9PJc zCD4bHke4YR{1%AjX-s@AsG;x(IaE003fubZkjV*qEWp{Va>cK8AHHI2 z15|iZa@9A?6tedL9M*fTqosAUxJi-l0d0j;RH1p%_5nB-+X(UICvrSy!)WR-8g5RS zbL`LG1<6b$Qj9)O*vuxvT^G(KdKFQhtb|r%y_S>yR;zZN+vAE^OA#D42~hs4lB!M2 zH<+_;oZZbY);4GZ$*heJZ$Zp?Z(BPYuowyWxia-avq|4ntlu9(o6e)Yof#XQQG9Db zDc>`5UH10193Ld8pXqZo22Fm^`|=YL(gd6PT=QRjQlR?xxE60;5GTH`C25%{Y?CtG z+lr{Sz$h_$<`G<-ff>E_4htw*0)7{eZT90C^#RH3&OkD3URfD(z;Ee*V46Ph05ZW( zh){LpGK>4W?Kp`M1t?2p&*fqBl7}PlYx#i{eoMXwB!)rkG_2xPpYR=p9T>X=RU6t% zkgYt!015#XC6yoQ1XQ=Q{_Hb_-ActCoke=GRcIl@`d%$jh~>vI@MJ>7x}qSRf>_*P z<1`_u#j0i!vl6BekG|AtIl=Tab(D}-E{&JKBtR`DM;ep6EA7E{7FgD!u-+rnX}Tms zE0S4aPYpeF+xp*8f9LZx2lfdqgX^J#OOH#8FkjbJxVq(@=#e_Xr znmP>3Iv(=oyX`(igMKTr0?=77l(q>-cMl)=bN~Ji9jWKWYvJENB<|M#JO-E<8@~c% z3V`j87&Rt`8(R~2-BCtqv4_krS>(t!pu$qEXHdLfi6{nm1wT@`90gpZC!$}fgV1Q$ z7CTZd6_4zWO#zoGwexTrbArO+WH?R9qKfr8-@O450jVNIg^ufN7ZmxLy&;y*e6ewi zS#&hhiF@I-QA`^85a$#*;|N%t;r;>H&vYTR%6o{FTeJr4i&hoejB$Ba*1U}$AmN_7 zzVPoYIq%B%ur*=1VL!iBM0>gs#2X$#o@EcWtIOzd14;M^pxkX5gy#y{_qgrLhxQsF zO`0YqGx2t<*233{vG}HFoIgG%H3)ulZ#lpgs-wiyDR*IeU_0&>yA?$>6#k+vY~Q#j zE99&3jG6Sb+V%Tv=~sgS>{;G(rsjh{o|1^D6Y?3C_1+>CTV5D{OIrAv=HeIWRMFrt z0#5Z4XyHh6yL_Q`kIQ^chkGw@D6gZsDx|wGA=}i<5@BZhi#*oH=DX^>ps#r2M0Qin zU)@&_%7=!4Oxlfqcwl}bK!}`}IglkF8UZAHp#QZtc0T^eQR-NfL7EX38cI&-vexc( zcOLdWy4rV_$r=nMyAonC5ujyu-=c?QCg4Jj&wQGRPyX$YQGcclACW-alU?7=Nug5> zJClHuUqDM#o}5Ujjm^2GDb8uPAtyll*i`Gsbh6x7C)SlirPf3wX_(=ZGlRPK)j;1w zeK-MoTDT-~cuSWghm?|~NV3X6*9N9kxZ>J2dFXWIp2y8j#A{vhHKP)$)kTa5L;HG4 zcZdq40VQy}635d%0jsmUFM{?DwE>f->S(dH(Qi{c*%1lE@6W=CB6|rjs$0Vu2}(;H ztCc5+{`*wt?iC-U9I(W{#v@_X2k+j+A;IC$Kyjm^Kbgh@i~+J226&%1cI}c$=DuOV z7)LM;%$$R@f$#ezh`p5CGbdIV*9$nk#r3espEIfNsHACgZ_ucJ>Sa5e)(mwCIv|2_ z)~8vfz?aaKjWiDQ%qDD$ZuS4&o!WOb!MprO@>=tXLi|Zm8nd$1F4n%9DtnDlZVi&6 z(M<ssYx8S+7qPOht43oTFT z>hs>HA9VU#lgp;|(CXj~)^1MTQE|u;_x0JItmsCHNEbT=Ty^9m7-a2Y?i7Zj)3A>T zR`=3robmYT2;d{Uu~eu1KwT8KW3da9m^vzB$m=8fz{TT@TRNc>YhHUI4*$mrj9em6 zr3*3q1${b{qw{y*v9p??JtO!t8B4U3utnS6G%TKC7gxye9C9!>|-Y>-u4hgi=gP7?B|`Nj`%+JZk1p_A!(Bt^lK z!Ins)={2dxg1UbnHsB6vBLa6SE4XNKj|iocK&TRk4g2#n`6n9B(6jqzXXnFQ_11*Y z8Moxleheu84hWVuv(t`+A9(STN7Uy0^=pHR=Pub>VYIBaj&ZXs&P1@jw#?ANm)%Rp zK@JZ|7W|fFo%Y}{@mf#wJU@RrF`2K4i}qgahB)2)b9LQak3jJiLn`wGVPt*OUSj|D zM>nX~th%)BUTSSbrnz%b^rOPyXQ81_83gW*P*(}1yS>T6i#NL6>ohh33RN|c&q+-{ zG5HOmBek=VtCy2h>S-(rdq`+@BCM4V!ms*97BMkno;XAMysWb z>M}GBXCaY8OCWwQElW)U%`6;p_JYzD1E;^eNx`TsYdZ3BVzJ~#k`i=%ucf$cTTqWZ z?^+~lARs1w+b{#(9OnX?fhRwFJ2;_c;%jp3qSJiA)Md(y5%HxpHl0lP|G#i7CL|~* z$P>ufJ3sz5nO|Ox@@G5X2_4WzWI2{I`AihmB!@ixHLW5AsN#RM7G@;!{Wh9_5l>I7 zKG1~^=)cKQ1xFAkfI#!=&`xuMltd5&%)o?Ip#vqy;E6CwzBw_b4+n}u^~fp9vPVrn zf^wygCVkh(58Oi33zpJ_@MUbfHN^Y$5&GO*(4ry!SjiPjbKOtyXbqI1nGr7!2e zFjthj%}RzdCXDW;Gy!`Fnxkr^)Oiw-aPM&AkJ0|p;MhWhtEsiYw;<^JN0<)c;+wAr znTWGzwrAd$dLtBF$B9MAX;eTB)-oe%m!HqOtdica%@{mdE>bd=ABeUB*BII*-Xa$p z#Gz&ZDRtHPM>|B}vA^Tb6)$tToESn6@5(b&m+N6rH2tGr3)v~uOn5>>mw!b7jU9H7 z`-{ostyAF{zw9GMVv>>>oYv}yo1)!2YQx>xF*g}T=N3j!15SyUt0MAodU?jXaz6z( z^oejgRRI&bh5rA#<6?ARpqWtZ0X2e){5{;=^IKXLf3`0#Ee!}`YK(%qh04sJk{5vU z9LFADw;XKo8cC=f_iwL@E123@q7G(Y43klbtr;+EPHF^W(AN3QU{)burIfLo(+nqw zm7~v{d`P;f%zK9(fsK(S2jlURFeNoeZvYr83x(a4J~%@;QJ^wQSpmJ&Y+*{F(fK-i zB^igkBdk@JC^>|Qsp`7(%x}ea@wlr9>volN4WlhC3X*JuJs8bwwaPdZTrJ=l>(w{j zS9+M(D8l(-`Msr>Nu(7ZSp7qqk6^7R>ijO<8qs_@x^8;4^~hN(a{m02y38Wrh^^O>3j!V0yDfMUxmxp5`h8(hl*_;>ay$i zeP9M=wuEGy;?T;biER1%;_J4wI|F44%%kPV(t3wq6vmSYoXb{+czIuB0f&S^YcOhp zZ(Z~8RvC#NV)L{>$wLi@A1|^0jRGzo2_otN!=QIiTg!`u3cZ$cx=~4U_>=SL zi_Lp9VJW6NX*_~ zjp4#HviYippX9X-pM_ORm6&H^URW19J-Cp3--jY7QKp1r%Fmm)srjwfMBkiUTc z=20wvS7Ec~k4L~4_y~}3wKdPM0bo-23eAxJf)H(*mFz2L!+>6l4?+Evn5eZh?62ge zr|ZE_SwC#PPGDgqyBJvOyWJ!aD`y^f$8A56e6^wEBFRCnUt9d#*hZ*GS1hP)|Lxz} z{5ndkg~}LdR6tUD1d~%(IGXHf17QHUswTT6$9tr`-S8~U{XA3PGmD8ASLyioN#Mc1 z^kWrDRh1vPQKZp|4wkutaVV|N3uWtz?x}lsM^gj|is(}+HY^RziR&v=*Pn~RFXWm8 z%g7b{YJFllHsV4BCiUc7G%PPDTF8$@MEKaScPEx2I%Vn6mpYox47rQgKejFKmB$lD z^ljiF)+&DTsca?QtYNMicHW-sK?@Tl7koZk`>0knfpAy}foxSS7rT-q!*Yt5@dMrw z>5?!9UqvNvzxRI5c92PI9;4M}pBYxd4WN-7nLDp;A$e)==+PN=N-B?+1cv1A($)x; zPD+fV;@0Qf!y_X6gRtkDFKVbu1iV~rE6nIyPurd zldcmT6x3br-5pHfVOX8VR%`&X-nQ0)NDPl6(^MB>Zqnj!y{_Qhi-!c0C5@@Ial6P7 zl~O9ThO*t(AM6ma;vNR<*|pS4GOytta41CRP*$5aZ5_2(q2GdQ>HR--`7b`E;{Ufc zqhUY}1?JIx=Bj7quNi@Wt#P}Gr4&A&W&n1!Ovu#B{boK^^lU)RL}kE1i}~#drgEJF zlVTV{^mBZdI%YGeuEKV2*x?qOMrtCg1&-bBeQDVz1pWGa2>NRmo1^2OSab@4t-!iM;W4r5dUPv>4mXfB0B$=>2bj&67)V%pqdi=)t62*Z01u8awt-0cD; zsY{1FY5ao=XU!(*ofbGyYg4d;{GzS(c^(r2-?$Z^lbGV1=m@+`d2qf&52Y0fk_h*Y zY$n*1a<$bChB1(vwjXl&oZ8EdL-JuWy=HFtH%`uOma{{7U)-(J1CkC7ke7zzwR4T; zLKRWTAATRwO=&KgB909&mG*!GVb7kCFcU(flN+rG%{>t~PX3#7rc*o5Ba zA{8B#OekV?EF6CvE%w&!IZ~h-(O+LE!e4a$53-~;`WH|hg$kkq(}9M}6Vu0J{V9vcPfUmdM=qU20@Fjy9bzrGXEZH&nl0w2tKM)d1#x7@nUpK%9p?KkyW zD3VZ8XJo6}A9;L<%1(8Bp>=Xy8FtqC{My$ap{|3wY)>n{xYBl{nj^Kc`uTszBr^=( zXJ94=UZyu;qj#17E_LUWapXEK#rYAPkdgw$X8qy?_G9VL2*A!zAYnunRN#6|S`kDC zBXQ76$rYXNf-%!UP{y@dR?*`Bq||>i+3#x3=#(9K7B4Q>x4Th`VMc)G#n4tf;RoeZ zq(Y$o@`2F?%AzsfEq`4!J6)HcEX5wGer}%oxDcp+mxK;>{cJm?9e5L+tKzD0? z?s=Zea+O7N+BZ@4J+$W7@<(h`^W1~&`A($t#m=QPnBQ9Z)(1)&WwUyW|HG4(CO>iB z(U5A^gyGtpm72~(P#C)u*nz0F7w(L=((X3}-uvZI*m2YE%P*jW934DtTF@0&&nFS> zsT|5R*CB@Wp0n4CoZU`B3@n@ecNV|?LXN;x8BF#IK=Ykstaf4c2nndlQ|${jt4d`b zAlG`-p$yS%m_ckQ4)n9o-|T5rKYHrV`s@8>cn_^cYOt}(^cbQR)XM=q%?IsYL_7-< z37qRBeD&U;r7Ghso=e&S1(a+yIBZ$Ba4E@97U{YVB=2$<@mRJf*@BL<5IJqKHifCF zXurLk3HjdnKIl&eRY(wV=v|Y3H`$TXhL)yaZOd>Vqam0!zv!X$-FvTho41A^FM9|I zd#QfsTUp=V5PYe-JRP)tZ3L%fh7y5K6Bu{qv&U(|P{%1z?qRft_9@$!M8s;HFH&x< zdQ4@UaW{LxC<-Fwapgu9A8|rFp5l z0i~s20M!M@&#vb%dMIVHTu#4BCv@@SnTW;ES(f+;jJ{U=Q?`6P|Ma$FEWo>DgEWft zehYY(HsdEo;3nWWX{ma|Ukj>(7_)k{J5yN4F8Gf?!{TLO*dlKtn%|jF&=lDNFcMzq z8sU7Yxy&GcZi?mZ1t%V#Eo&B)t4SxJ6py@cn&d^kfv}~VSojb6QmCYow`bMSidKGe zZ8YDNZr4#@TOtV#7R1vP>H5}()ARJxl6H3rvQm@an~#j=i@QosoJrkul-6{;uaF+O(!Y;i$QMJdBTQ z$34cAuS1WsBm{Bj>RIQDDl89gk##$5{?KmHYFOlXlgf@o)ZQ8iMq1uze+dR_l_I<^ z;k@q0ss=WMFj^rfDB*K6cA~LviWRrAOwaqpSDLqX;^H1qzekWRU*(EdrpMHSB2lw? z+(uaK|GWU^civT7(<;RAloho@D)nwov&Mz2E_ee*PaP`OTJFc{#YtAmot|8;iCbWd zg}VQTy%YcMBGmuyB3LmIsFhVzdDOyd2Cv_)n%VdsIT7xKelvc>LHLa0nS3}B$L0>`YxSrbOLa&4 z3S_Q5sJu7)`fk9|Sq)4KG$mgW52r?KoAH=GIBh?lue;MZR4Uw4M0gcAuqJSTU@UdY zISI&sFYf$1dp+=*bdH4Qxv;}#{eqgRjjaYqN@uku8EFGO-{Ru=94@1@*>#=1{+qx5 zrhp`KQ+B|5@X2v|&7i%jd=0^o&bLdHCO<-lKubAnCWSpyRXFH`Ob$CGgPUmin>y|W zJrazAef(?MmQQXp``>S3locT)nDhbs2`#iRwGcwuj5;`5_IP;<~%F|sp zoV!CyJYHVG=+?_(k06S9nF-SMQQed?a({DlP!L{%g?YKTBf?B$XJ7k@$$h>T^u1lY&VfW_8UW{T9$0A(|i33@Z+%Ug>oruPlmrO2>Ebo<& zw4_a-5|MOiPP;63!SL7ZesuGXrGbIm0;4ROl*vN$C?Ovgw`E@;7w+cGvW7UAf+ zNt|vyc6|BYD3K=&V6guj31$i2VMQ4V;Rx!W~*v1nd( zl-I^pt)=1%>WZc@lLSRt8^2{tcv}}N)oQA)78=vfH9(jmch9Z(1u^k0C1p`Yd_Jd` zTXHgJ4&}|jCG-}UEu%xaqD72>$ zE=-aasreYap5vE*{m~37Bc7Jc#XRw=~Q&u z(q?4p7d0jG^6Ys>q;up6NPo*6t+{T#S`%r&q7$6#!f?+Qo%`%Q=v!~0r~~j^`R9+}4SS)=<-8WbeK4|eOG0mJ$@TDu5qRb@uw-@Ss%FYivB`%2;&Kenp@+S6m^N?1D~^hjA0njy$?`<`Mv~ZFZ{2l)BX!nSx{qk z|BY2%Sdh+)N6~Av=YW9CY!s=_0eIZ__HdjVL5cBM0s2JWkn%jj^`FsiNF~h+!*26ok=VH)8G+Ppq!Z1I`DNIeBtC-} zOJtPFusBlZvzuJ5z+Bm9M3q@=iw0ji4=!orVs30_(uC&Xe8&6zN8ixXL4Ks7d}K z1LY!d3shKyoywZXn%5ddK;c;u_5m!d9mn%q=5WAn5O0 z*g8q+Zco;8){$1Om9C_UB-c}4jFxjRuj+M61vu{`Te)T5uSGn88{>g?Au3)ye8Twb zH6zoy)Lw0>th&3acj5{g&Sz2xCK9izV#^ZsXTGL&6m$u<;A?&BRyHhJ_*F!vSRx9TRursmnn6jYV4B7JII-o?h^z5(rL z<$km=+U0aCv@mVw%@K(lI&}yq{TVwpL_SQNXh+FZZud@mvhXnGws%z+9jAkwr4~!M zVjP!~HYJ)|_!HV5U?CN?=V99Xhktk!!#vHLC^3?prtHV8q4|!!NuzEPP z5XKvLkCm9?9nN$u^CCoVEEj3{rZ3Rs6$e9gDmrOx-oOtU0+d|J)|ZBkhn8xnYJb2sjp@V7AryAKAm$YhG>f4Pn1d!+$xV2 zm;IOBw4lb%FY`?uA;9+WwetJt`fmBdVX*Hu(Ex3S`-yIa&Np~ErK~Q1ok_tQa({l# zK9MbCh1v7hUa4U0w>QH$eu2STi4&@2W*9iwk(g)>b20vq(u%b@6VMd3DY@Ko)1e^_ zmX8#&iq6+B529wb6N?=&a9Mptwj&1=gS=5)m6R%udqb6uanDbcROHhiAzCQ~@lyJ> zU^9X}9;T{G?2ymz3`>MTVX7Fk<({FvYL4hHtuql49CY~=&h&1(B@n?F5?>n}A;T)Q z$IH3~y2qr$Gg=)l)TtmLjQ4K%(44Ep;$Do>;PToO+;c@*B>hc6w7GKbz9kF!^!WG4 zopd6khEdhquhQe$vNl2r)u_ipCrtCKI%@+)VMs|2x#i^jQWlIx$+JVADw|%vtq)je ztN^^)avK;2U*7U|m-975Q9-R?PRvgrMSAm&q-O_D&BeRS>n*oq!rn&JiPOyeDZjkP zO{Wg1BF^@{rx*Hal_Bh5?s0%PzJzm`iaS9jkGe*@Mr%slUJEA^WD3quKTD}kz_WT5 z=Th}Q+W-&UKYhOO1O>Z8aFMznWuIi0>`4i&cqI_XK=$}^5H*2U^F$IOc`%M_(4*su z1c-`*zwlh~)s(7`a`6X@%lLxz%*+bX4IkD$!|Th(XT0vh_#2P(WCrGzvz1@58r*S5 z3zZtH2=3Iy{DGI}_4Qw|BiC!jPN57hO2c;i%Xl&m-!gihGvav^W7zOEqAsvCA_eGA ze{Gx4HXneHZIh$O~vaqmBJYtQN*0-$GfAAVwS zk#F-56#jBIwHkivlgh(%OOAy^AP(v)Y^x+$+dWe88kF9su*>-2onrQtpKBPO@z0$e zsFR_93eV|c#i!Zn@+~8i$9YFGcP3Of#c}Do9bqbw#qQH?+^=xCThz0sIfpr7={_+E zH!nR8O9pkL~Z9B>T?4$xoH?T8dxi8ayIZfDMD@b#xIvS>{j`c+@>F|5ti{QNql8 z)RwEfO%1qD{rJ5J$O6QAMb&l*gh|(0O_B;<^kLnNS&6##i>lI(vH4%16x1YRUQve{`uzELKK=rxvk%jI2J z&DKpo)NW>g!wQoV5bfUn=jAbe`m%A^u@~48o}YjNh&q4EcLuND#jLZ-jfx{T%g8e@ zhm78K+={3jf#l}dd^b@-_lb|>|NR@p?M{_4H36JhftsqQIJwB>j=Iv*fWwR!+8QfQ;!2olAl!k2s z${xlPa)AtQ0dhWH#^Aysl0-3Eg0ithYNwAIU2yI)p|-x-ja8UOn(#IDfgVpcnu+$% zZc$11jt}`Rc$j-i}T zonCT~8OGFWVqQDu=eCt4oeAxtPS>I4zS`EZZySt%bTNPLQCk9jFB6c@p&i%2Qhv^4_dWzp!@&t_eetK|mH;QwZO|(1e-lizGi-54 zP4csz&79Hmp;oQ)_D2bSSw)8Homdi~=)|)GY0_@+^E@~`4^Ibzq9{8LLL8A}rTJy` z{!!<}v%D)V;K@w*cE#1&&aU?#h7UmPX7w%PCq_?jZ}6HR@r56Be<8uVco&fR&Bc#^ zJFK_g^e9EU@qVG!ex{S)mJkO!N$%A`M;afP)V#?1xOR|y#jF;;@)xy)fa1@?uvi(T zkjs4$jIrFO9lEL6S?*sRhHoVRZZpzCRyO~fIcn}};KIzcMP83yW-H%APBL%6bN!&6 z(u^Dg5>h&p<30OzxjSCjb=2DPxtW`B1gfwku8R-DK*=ztV4vF?GIt0wINhPjJIeeb zqrRZL@QuE5t1dbWicNM{teX``&B`#a*mE2nJwv+O6`LB$%XWB&%>C_#)nOZ%fFQ{z znUb~th#G0+=hXLblBEc0mW}iu@jAujwQqBzm^SnpkPOjQ6|d;BOSz54{#fD?^v2dD zu&U*P=FdbsLcP%`ND0_GS+ZGm?_{&)c&m92*55i1VN?{E&KVi~Tp{4V9=5JnrJRo9 zJr&pW82S1A?QqrYC9t7tlhTy45YXJENilUEULrA$SEpzZdT%Im%1Z5)sSZy1H6APF z&zhjPv2qS4?0Rlg+qCzpwfDO^j*t_=gH5>3ZFw;!`Zdrd`U6+!U9<<#cMxr<)(&TGq}uYlG!Y4qOmwoaP2=jQh9yPlzYOv8w=ss{oTmo^%Dm z3X3a8FqqF)4kNusgY7$84~TIL4h0tp0b zq)=?eIG-!IFN~8?V)F>`OQbGB`mt%KlFhU@tY8dB7Ajotr`5nDLuY)vPFlwOyTbuD z5GroWIFSHd!hIA`3lsb5S{%2~>ME_{Z^d@9R6nO#1VU6nI-vc3JY7?CrCYP@PRF)7 zwr$(CJGO1xwr$(!*zVZ2o!s5$od4!6PkW42>#J2YYtC6VCo@u(1n!>av1QsCqi5PP zzz<}#qRadxV_L`Y!&_Wwt`iHDf2m{cMPTkx%$@zCQyIER_!J*XD()$jehJJ}CH0fQ z3?fsRjvUcKj_@Da9WxHbKWQ>^C79<-7Cs@T>^%Ih8O2J>Hboj~R>Fr~Tyw$Z&U~?rNd`dtmg~MU0(3`+FW>nq6utpRZ_|cck(vx%5#ZVctzD<(tH+Y zS6Pu{5;mZCbZGwv6xv#VOF`+aY;0H|mMJ6M01U7CQ+nQw1S8E9m2z%--c!E(l`B-z zXAxlrxb__0kA=?JL5qxBdlFwZqKXNb}>z z50SFh0o>1-1)z`D_0czOBWQfNL4nG)V<9t_wbD|4uOa^vwvi5n$Yf$Y;-IlxN<*ar_ze=IvUJj zhXb0X>^fd|&!)c2lF<*KP!6G+^8q@7`${Yy>jH=nsF#FT4U1Sq0duSZt5LyH3mvFm zwHP#r<_A(Lr=Mwta@zW#P9zb5hS8}?Cb{5}21hiAY3v>?#c8kQ1+a+N5#vixOR;AK$z{Aobz9DtUY)kP%;zVYF>ylRN!b#X z*4iO4j-Kea={+DaI1R7T+?s1rY@)`LkIo(cRhZjL@TsW%3MZR@o^beYxrfnz%lkR} zrM3=Pq)7QqWPgv8=LP~P7YQ6V{3=3@%Xa&l_jLens#$pnnS%6qqPDsdI;+iQWOQ`& zt_dVzkx=@ApUZk*J0CN1v9W<(Hed%N8T|3p=jGKkfE0|1lH4GT?Rv8-40s@T>C2TC zOW(&-yZwbDP%)rmusMxG4fH62ioDOs5wuPvR{Df*bt;l}D~0SXet8);>$y@xpL;Be z>N1R=a|0VCc!pvY*9XAKh4~>TI3$pqX#Ot3sbui%naTVPaxB**U$Uy|x!5uJqoYpb zHgD7}DkQg`;e3XGP90ooh@C#t%5VJY3(1 z#IGGZ$=Zu3N$rRMX<8czn}DW_2FyBdA)#WmVWc;wk%GKXu&hDr6CS9?qr7%oNb2 zK50(#^d$xm&#pTEH=uWIP1q)6H#KySBL9MVBZgIJer$(Q}7NJju*a7ukKQ&#vwXnlqGx13xpgKOq!ih6q)hX|b z=54l(x?js|l`V*eWNAE*f1)=s=Agc>Y?8cT%{r*zS2_S3YFeiM2m7GH=1v8cN#>hORO%Vz>I`FZdxfW__0sichxRj&Bs51}avI*DUM%++G#Fd>f?GU30Eo z-^VpD=88DWLmurRPI)Bzr3c6^@_=<|B-7I(T|$T1-c*-bLOixV`N!l5$pX2HM;9=s zk3xhRRXLtG6Y7w1h{Ap$2jqsbOsj>GcaY%cML7}q=-aIj`*xECemVKmJx=f0(dJNe z_J%R`nOBpVdJlAt_6_o?e^tXOq|P7m1h44Q%dV-exe331m$khA1T<>E)*%1f2MaZd zPT^CYhp7|M^#^mca6=^eHo%_SbwHKzr_n57#k(kil3VM68fB;e`E0f-QA{yP66BFg zS?jb zwyK&S-WE|v5${rYsO*C>+2|<8dOD0?F+uQ`k?9s?>cVj{p6pucN`-<%lyBRU+5Ej* z!xp7KnV)#Tr~P5s%>T@mt@_OWnPpr#t^2uQl*S|&qefbHws3aLaYG>jD%0S606$lT zj+SJ!>JrP(0aa&vuvcoc5jxfmyV^r34w`VErH>^o%5u=Eu$r!s09nMyOj_1^&?-@S z%tp^*jkwd6SGj>Ty`@PzKq{+J-su~{VqN6)_RN54ldN^4bO7YwSVP?@bu!Xf<&i%k zQKgtpxgySd)}r2Gk2|^>G0W3X?oumq91w9id;z^)W^7Bmyk9S!8s#H3$gbcToe}lC zV)eh0@3t z(YZ^hz&=0GsEBQv1-gc<^gJ*_WV?72oyU_jjUpYrcu~`=6`;^IALCh?)!%jTAB*V^ zNW=*>q`ezG-N1_=obP65+JjD?@hG1)&JfPULTEh!OetB1s^=5&W@J5{x<9Etm$Q*a z$Dl#?ka=$rpKJkIQH{gjT~)9Pt~3Ztr`NO0jB`li#1Sq*2pk*3d<=Aka#;XF%7NHy zqD=H$O2Ub=5-8@3rTqE=gwMm=w&=}LWfy|JR7i%y*RzVLI_Q2SCD>nFkvtkbNkBZF zH{eOh_}!uwU27o}B;EkDXp+>|Mwj533o$jpvgn9gadeG*wQVsiMc?gP!usT!DNUK? z1Buz)REbkcHz{SS*yL={T2oI^A{M~OHNs_ft_s;^wawwt+8K82mAdT;nJMV(TyJIy z4)zoHNQ4G&;MgwcjBBnAC5GAyT)I!hb*#^w7ep;_n4JOSr+Lr6WEC}FV{D*#0X0bB zA|;=_pIfuFdE4Nt(<*mjqxqik2Q0JlBz{`Tf#7_}!y^A{1+G|G1~M zB6j%uEf|4gC8*ma+E)v1w+_#Z0+#_r=LE!!U9@6=n zbe-5tVmm~Tz#;3dqgp>>WkRZqi1e<@*2~2)&jU&Obax1F0OlfAB7A$7GPu&TpyZpj zsk$dG#CTNZWm;{tK0-JFszdYT`b^|qH+j9nZ-ag!=OdIvCHbMk+`CRDT0^?ffB^G z-RT&k`eD!@Mz`O6#oMX?vSdI{mjammF!2a!gMf0b5ZEdM4|zmuIemYOVh`{g83X=$ zDGZJtrEO)GJE}@k(5gTJEe>KNU9yqhf9iyYm3rxFAIGu?|NR)~V1sp|S zVK4zjLZdU~)ZZIbRaNj94=kq^$O3CHyWyRak$;qgeEA@jDyeiy7H}GbAX(q|L}8Gjrh1o`rw)rIJ^{_92B2umh54r6-zh$viNU0(*W&fMo3liV;FGwL2lgu$yPdM z8sx@_Zr1ooErv9h2+~a!;7^2^5;|!~r?<9ITf?mU_H&EknREslwyW>q!=u6 z(ZU!->FO`s3TZM$NcvsvB*?J8FBMzr_-Wc2lb&>C*dB|~|VXpUdd7LHrg-x8e@q`vF8NkJr z8;oT|rqfr2{SR+opCBC_Pl8TV*j(AH&FjH%En87*d zg#r3i$z(0m_JY;a@{kuWpKCBVy6L|tNWtY_nI@djB54xCqs6Z`OdPj;1VJ?#oz7>5 z%;6p;&Lc~J|9$Pk58?Dc!`28Va&ft_*D5;fGNHM~fQ&>1Zsem3oN^$EHxlu(5dAWW ztj3bj{^AfiNfp%C`hm1az7zIc$2k+T3}IbpV49)&KZCwmylZLwvwl?iN~#QGOH+;={iTL^1!cwARg1~4l5 zlXr+H`r-=pWg#WCO8^ol02V!%Lp~m-dLEXUC?UIiQtlj=l2od-ozrNWT}EV(c#npdbio6ZYDlFM)i}Rk6 zqC?W2YR+DZ_{z3(fW^X) zTice6VTIe;AZ`2H^Rglamn^00FD58n+7Qap>h}qIQl7ToK@u7Rqx>kE987_R01htf zrO^4Y4$*Xu5X)da7Y%FX;=^^d8rasD^tDrEa6x@A@Dgz|V@cq&-1i)zM%G|4o6M74 zy95TD5(*vhg>=zn%aRr#o#X>>rk7Nb?1l&nts+iK^_XjK~trJmSb(Fq?d z3cVFD9dgO0e0$zqDmnSFmg+-Q=kT-RZDe|JzrM$vw<(H-4TP~Y!U<5usd#v6+ ze!b460K{F0-38w=B7AOlG~g`U<)E~o4GKvk4PBCxuS(@rCHe|NwBuq9{Zil*-D?*I zlw%>b78^Y!mCHhOxkFcs5de#;0l&*~wV}Diq9cJp7C+bmTVe(#TM*N13wb}&uXHU- z?XW%TOxnz(eQK%yt_^>1a~E1c=S^Y?%_x&iGcDfeOtQ|G0BA&(#3)k>yvV{ zd3-5-t40BPXNqhwS z#{6Ba1Xwguf4Xopz*=#n1Vh7}_;7*Uk9QHcb4fOD22lAvQfFvx0=!V@$SI7TRJa?< zgTCLp2XHM=^U4uHN)u zNKdB*D2p?3#CBQ)<&zO`eNkt^_9yM%F_$7FSoz`HL6EE{F)-APzFQH!uO8dwHpY|U z!SRs;%JGU?;enEbeMG0BWA3q?SR5$D<~(|*H0EF!`B7)P`jbLv34;Lyv@0(}9j&T6 zT<4kXD=cY-Qil6npzTk)=Q}y{5btFAL^O)xn=K<`9NIX*6`HfFb&H)8XQ%@ea@e5l zp`}V$vKv>sM1&4u8*S|g={mOX$mi=Am!1AqZ;%>f;d!TvY2#vSYfkp`W~e9$f}?%j zJKyNf`X;UeAR%-58-9<;;rLB-4HwHMN$K#bWd+Yfxk_HqU3C_y`<%t~&t~|Zs@g9kc(@yQ?lPjQ#nXp(G%GF=gI$*`8)pAdD4TA_sbyI zVZeq&?J}h8$5<_yVA(_rzx>F`fddV25Ybk{qXPI&M)fO{Z7+fHY!VtfPnU!=09RRa zbArt@81$0K6jIFwUxRgz2MB=$e6m7dSfP^k&`)_)bJeK>FzJ<}hkC<<`^*KSrz%h52u1Drt^(X2 zAtF-cmeG~KT14a)sH&J2xm5lNYVDpxbVgQ+<|peYLWvvJjg(9e;1dULBMSxG4&CxS zqS>4oeNWLvH$00;19lpHqr;UJ&f5)u%kr#Gy0EOsU(c|(95mxWi|=j8tFUn-hH7t& z=n$=o;%U*`+w&;%oV*Dtnj7!DE4jnb5(!%K);={(QJp?WPofi(nWy|Ngr4Vsz$i^r zk&c|ye#q%|@uX;{-ZT@lYNV{BIyqp>EvDmh$4-@TWl}cWW zK`_TVeXP?_r_tX|lNa#*oR@?XsSZ!XCpMT}ty#690H1s9tIT9%p?uRbD z%FA43x@A*EmNSt1|~?Prwx$GTLgv-7s)5_ z@^`wC(2rL_^18jSE{Daw$Pud{s?n5V)p@l>on7n4w*ewmz$DYRJgH2@(W9A?{+CUBg>}RKRTPvQ%QgIBT!yEED{K6O z!NL@|y2OXZhQm;fQjjhxtW^KW_wg#RFj?U@&iEK`tTixUT_c?9>w8`{D~4{j>Ox6b zQL1soF2KTDg51tTHDMFdfcrgZ_AbbWJ+;z#5Nnj z*?6$5I}uXxcac&!$U)I1QXeYrVsa8V&2>X_-EiRJ2^K87v#t5yIQa@bK#7PRk>5tOR-9 zz?2r-#^wzJCkGKt+AsF8y_N6=3?TtT))4y`&w7tv+kbRHzp|Vtd5`nj9 z(Om@=hQg3Oi=8_qw)jpgE)0D(*;9r3R>T@JG?%z zp_#}S=H`;|SW$2aC!??FJ9!D@l(Hfl#`KxV@kI`SKGt zEjLRh__DOhMtwXst3!H51{-PZs2!!#_x@ojuHV!7Utt+w6zyj(2q~6=exfF#?AP^XH`fgZq9K<76c4l_N>b#iRZL8-CES#w=mP652~SoZWh*DmmC1 z_hNZ!>vy$QQ-cjL-h4lrxMkPrn*xc~N(OH|(DoXDViT&rby})?5BXt6g3s6(DOn1o zw0&X(>uGF+|wSAKS22gxY?OoULT<0fUSFMBd{+enhk%3yjev*9#EA>Q9 zOVt&N5=S*D2h=w?bW;ih-S+tyHwtzeND3Tgkq9qW`r8x+3_x5Rw2bK@n{iK&=}N@=ehrBe%?u-!+u zhdd@c2_C$xyeTG!J@@Jjo>L`8==P0#8e_#YrX;LD$2(T!J@Zqr{~4_ui0(l&hmoVd7dOCC^F&Qg?75Iz|PJ8)&YyuDd3c%5%9 z6U7q*IlsL8aQ&EAb4{qp`$Lxq+1=RvLzc<|9rvU)2bmfo`!U5>gS0$9t?RN1!*}<*;znk-Gywl(hU+))u~b zptmA1!?%?d-c#v>ZHMqc%C70Nm7Cu_pP-Wu6vNgiftuAfP>>^DL>uf=jgA`-(U!F) zdTB|ARGcr$)F?$MF}YL5$}qHsm~G(IRlLd7=@@Aops3X_{1lk;LbtmD6LW`)Eyc<& zj}JRRX)|))s46Yj2uOB=D`>Z42Wpyx9)pluDcj2&_Q?||vOKMKZ$OeM3AR#<0E|9N z8G=n>xCO-r}$sD)5)GB9Z#P4u6?Y_q5T^j4s`npPF;9;`$B79Cq z@z*qb@y>czPuSsAY+ z3{HHbQph$CV~fETcQRUCoP;wL=i=D8S8p@C^MRxVDPj&Dw3dRE!nQo{Ix$!+0*;_-+(+V z;2%p2c86${j$)$--%57^O68i{^`G2BW28wD@mdwDAEm#vqYkB=7ObN1+&+m2IJfxh z4Z*>c^2{eMY+ITJl-GPAmz0sd;~S;??dk&g!r^uY&|Z;jJ@VCc1{(E0F965)G0f`r5e3a)^f|&oqge_Wl%l@MT<`r@7ox(3 z&MiX@gr^Ikeo-T0cQ$Ub>zS8*C>A;CHfSgnuHe_DDDWjUBOP{JJTsl;_WrKtl!0lz z;UK^!S-0f3dLRo-)!oe?mtDQ3n##N7`_w;KdVp4jb!qQvpHigV8?8eZ5b{ zOr6XUIaS5^+tYC^FS)pa6u{~*7H9PhBOh8~5g3T{hCZ}IN@$qAa&s(?q%}Z}E z9WJnUA5lgki&C{3F@tQz_NQ-$+?v4GmOK zD?JUi9{xmR%lS#bsz}qcK1LB~B%M~2zkopv1lfMKcYpQDWHCaoieJ0$8B=c#r+6XD zR(V2G^C$DwzS&M-n*snAy*i}-J$ayj_Wy5<;ybWVt=~p~XHS44V*o(6ULRr7z($x* z_{yJ(z=n%qno12O$8;;8PIh<#w>&W7o_-0t8~VciXYHR(eHI5sdp zENMMRYr*2;!PLoBga3J`2Vds^0*t@_OuoHqkFOBJ1AL-Ay(O>v{I)$pwc1qVL2Zi4l+9#|JyNca>KE3U6Opo0)0<-ZW_;r{0piV8mbLCO)X1KV)bn zbLTDJr2g8HnBk^uYRAr=WYYJUU7Svr5Ld1^FKKm6Kn<1bv@+kuQ&4#Zl4LFeQSK&w znOv$Eku%$@<)Yqp)t`cdWxK3M zuBJSVmu^nMXJj$Gvj64txEatEO*x6k<+|DDA&Kq}EI#v7JTawwzg$UX@xZ-!^;~FL zX4rD#T)CUbyFa^ES)jD#^R#6uQSJ|t zIioE3>Pc^`U!Ke`I*GLnZ>b*d=go7=K$=t%O$X2L0q$zihUG|Is=o&IZ8-(}lz>`e zzhIZx@As7zlwZ&(e&+Degwa%3d6mkdfzPLJP@yy;{r-u4wZ|MB2Ll4=w;85#vk*IH z-kG`Nn&2|h;Hxh#!O8U8TrBT@3iBbz0VDgJi||265>qvJ1fL$)qkeZA!R_G)*l9o# zQ8z=>diiE$r=eC;|Lp)Qe4E_iCNIq#J(ypr`vpp)uLh4k$vw2Oc1i;lg+FY^nW$i+PIK1 zZ-qBWbx8RD?;xtEqR{EK{S&LX`S;8Z9q%41pB`;oCVI*A&1$6d)tLR#y3vvmReTvm z2_<|9#^qA=lm-*YI9HWj=9DQU%$Zm}1q($T;4~s9{LgMFVDC6CtBgF7q z&ZnL%pq%>NEfQ8mUd6&=OUQRE|NHU%lGwr_ft>nIpFRd&iyYZSge3R8dg^JtTO_2oes{gawD^z6zn_H zDy}?C-Cvb^W0&%|m4yyQr-NHnDX!H>*U-!Jnq`>`8TZQwy_NN}rz&bCVmGjRGexRl zX0Zda+I=i{|C8pKVL)nUhGTq$o8es!UWo#%?+KrC7~r~G^sAsG>WmOEFbbmOg?Q4G z{n^C!z=lLV2P$W}#Tk5D8EEUz_LbV8;(k$VSj)x1VabcP_s>@?$<7xq=e6m#*ly#u z4u{OOhn4l4pnRojQT^0iTum-u7Y1mP_){l* z*DzY)q<8Y$F{uD)?n1IH>HPM>eyBKCPHdgf*_CPIs>_^`%98j+UfF=2u8qoz^?ODa zpO;LcQmmtBX>A_KkG7At_e=}blr1BeFbcQUD=LVuGw@01_|9U~q;d(;vu@O+mi$tC zG^=gSw(9136{G4C*7*^$uM>Vge`nCLQqPA~O|}&uRBa?y>EShr=0bmGOkB~pir71n zy$F16(ng6cGQBp5-ZMRv@Be&o$x*(D$r5Tb9*AaOKcW191K3%dP07U!ogp5Mhek=ix`GdWgHz_3K7$|^d}8*qATl! zZl)h?I^wXH=lv}B{Ep13LRX{ zxO{L&KISkUC9AH7hQEf?xozddR#E{B-{t!mB5K<4C4xqnmhPvk&T}Z)kGw_BI_m1C zH4aUvZ^%JR$53(io>)l*k1_8CrqS3yb`TN=hqomIOGAj-$O*(rue@+#$n*3`nRSSVQwUo6?=<~nj}b=OBmsc=qV0V(d7X#wWxJseLC>#4`g zrxFlLZpAkco&nC+>75j8Wyy=qHo%Fsovb{sRsVb{;e3w-xq(H9$t#?kPKN4XzByxK z5W#>=Ls+7wiDMFosrmQhtI492uK2eZrIAGH;xWX#NQ9~EuO!CNT>(O=W!sjI@e=#o zZ-hh?KjU--T2tUQQF&S=;bj|ZB7Pr`2d+-fbMTmf%kud3@8%}WNNQS&2jSCb6VYHV zMv)gq#wV+@%R0(EiQvf?{UKURLi72;RUf!z$j>tq>|Jj1{1MgRtt*ynx}G0+(4{vK zZ6l71xjXZo+0^9|#)Zs4ZxodigC&I!X{WLF(V6pks{w4Ih0&M2W57n|g|H^TT{{&Y z%PzB2ZpfDAG0Z;#l}YsL*>kqpI|Hvv`^ll1r&Qb#jkq(m_%^{uEPAR6?Uj8ref6n1 z>GSS$5RsO}wOnZO#R&0pjm7EZ$Y^Pm=4%GMqP??J!izSru2fO@g93d`y`sMI@SBA) zPk4N~pl#h$UeXQ~Dg|3p6*uq{oK7*!J6nKrv_2P;-pHtkMsJRdJEkl%7Z8{vWNG{D z=dv=y_?tnYCK=E_xyz6gNJ5Q5FD;8vQ8dX3oJe0>s5rmTcOF!R@>$Afrm#svyId%eCwkV=7mi<Blj@j3tHxuxErW*}^Hq6gLwNsP^aYm@dyj!#&eL7n+QjG7 zMRz8u&u}}Bg`-c|EyOI_I-mi7KDiI&uxi`{|sYLDjjWQ};&0%E@6TDkz<6#J1$SmaYXPk#pX zRe?)6Zk!M@akhRZpg8*;Kc}fSps>~tFV}Cc$9AIf-}A8&@=rE0-l|+cFv12BUn+@w zHAp?y9hpkAi)@mI86q``*Z^_~`+*V?Epi6YHa7c|bgE-Z(?buS*D0V(fW{A_3+$?yUGi#n{!*$-O= z>2)1>u!`Xn$V0s>MyqhXW&*r1Ch^wGjz^Mq^$vT>ZHBXJkZpUkeDgcS(v4dni8CCA z0l?t*t|rcsn;m;O9wBrH@i+&1m(>JJ*M>8?INQK96uNh^jews6b#rUqD8>U!Ie_}@ zIi6&>^SAo#_mnz=F;LmvIF{#WIUnb~!(GJr;c@pYYn_sQdg)QL+l z8Pn;gGCt`GKFocN=B(rfLWz|dg4L=&-oM)Ff&kv|S?%Z<=3Vh^%{8Ua$bVVO-#HyU z{hs&Y0|FE3bf?*3W=f!@7BLx0SfWJ{82NAFA7KIHBBg$YwZp<_QYeI2;Omp@Z?8N! zEMsG8zK@(NWyA6VJ43GV(LD^0u>bosI693oC<-JiD@@C;c81i~jrl4>XVp;GhkH!z>} zjF+V&-#@AM;k1O!Owna1#;BB%HQlZpue^Y*5tF9cjhCtoKgJfl=>>sKvRPaODK;lT zd4E|=Ab%&f>9=0qV-kfIKFI8je4Sf>BF;+#|5;=bPcCHFx-(80K-&}e#Z@ZJCOGdn z*pB@evz=5?vnTY0;W!Pzl95^W=;k+jHt&JM#pN`aJZ<`x1tG>k1dD!B{Fgg0{>>dm ziV7hK(%?kuiq!mDk3w%uA~Z7TvDoq&8kOv}sBChLgmA=FFV_r~!>4%aqaovlOy-r_ zjHH{QN()KQGj%id7n^S2*=~Q zh_z8@ z#blLjK^AX;DeSLn_@d$(!GjbuUx#8B({g06CF3wHYh4qB$CnjRy{@K+%K$LzjrV-;-8OwDhuwlgW#GS zsL^wn&<;4bADxRnIFAuYtad0p@rT2+CE1_!h&gQ#vOfZpEXsUyzw4=)NlRinVZTbQ z&~FtIV;}3yK`-8C{IP*dFQx?FJ;XJ=r1Eaxxt3mH@!pYkPUes05P|p$C zctn%exchbvz@0j%ouk$_Wqqn)fa4L}37foaw1$6|$!_;J_N(<8-9vB&3_(i7wLIzV z-^Nt60yl;1tEvQ$o9f!jYb?QW7rPHa-DwUcP@b=oFQJbfvcX+*-e-$}T$C z8uB0^OkrRPe^_p+j(c#Ceu(_%YyCq8Xp+hT4@A<=+_NKu_~v>73iR&182rm*cmd^F zxO%)Tof2uwRKTgIREHJs2kW)$aw z3Xm(p!%722Xn+G#6VsFSpqDY)==kg7AB8}#)U;8NEvJ~nwh`+M?&MDBB!NkQ=B1u4 z`xoAN_zRERDNIA)RxY#PdOfbii&w2ff|{1CTMlCBZ!ngc3*#9DJX*z(uFga(OVPq? zXB=tap7O=&RTt+eri5-zNsuNCZVoo^rEFpZeJFr1M1A3Q<9FA6KD5_6Z#AKxvPGD< zU_vNylcHksozGb1b-u`!=g^XR$JGfjcuBc?;}OKJK_nfoN%}9);M<*H@sp=w5z**D zHew5>hnT0dF0LPehI!tJzRFAEy~~8om}@o#c8sFJWZ2;U+g*Pb#*+j*xe5^DRB7QHk(T^;2nGbt zQpkcOq;!tv>tvKjH^7xL74k~SxMTt+mq2Q24Y$#z@`(suStM8{ha*2jWuq~KV;7R| zxo^2V;dllv(vI1O)4MDgf`=1dZ3Hxet7mmQ9;gr|x?AnEG?E;}hC~GG^?Lr{$y$ zVo6(0DdDL+qCAU4KXjE5;CDHY`5Ya;^+63IwA(|*Wh_s|3P`nQ*B%v6)<776;q)E; z0F%$Y@*j8kF}~3GVtJ5t9jIktkD%`@)4I5Ir=K; zxb=NX=)IL^DG1QWKsiRc5dL=Wi3g%#rVOgAoU8yCWK%?4LG5d^%rM)d>E0Xs2ijDM z{tMc8$De*vh5cTp&c1l@SAmd^m1`9jwk;raxa20^7!|hNal13oGN1q4b}AamFRwZk zTMM1Z-4AvR4qm z>(o{7+^D)VOR{OGFerUmy%2&#d5I0`d~m%)Smgt}TL)kK@@>=mlr{>5i*C{8P*Zq- zu+&0ay$`$E-_1|#3^VNs{B=hH4^QG6IH6Y%8!ZZvYhAqF-V+!i_!5|krm^kRmd6K7 zq}+M;=0mf#W;J5S^GpKTN*haXG_}bGqXt@XX37LW3=8Gw+_PQ9`jhy}LZL6m+!fin zI1tLO%*qUKhtx5x+f)8+^m;I3gvu>-Z`@X&+DcvF6aOjqlZV;q9rMp`~y5SJg-QC??N_TgMl+?4m@q7LLdS1fW z*E(yB`59x*X()XEOnNmyVniX(GF6BXCL7LVx~C19Z2RHhU|m(_sJxUN>v(xUC!nnI z_xP@Z&kzP~oD?k)6R<`8giTT=KZG@eQ;-xBzhZu}tkn3xd=+Xh0T`UAHQ7sVfS#xa z4`^CER9Km{ZizEVE&k`V^^ASy-bR0?c|4aFSXqQ6JEqUw2KT&;=BHV#bz-}O!aftk z5H-b8G%+N3AfV(l*2yK$r;6V8vR^#xLKOeFI_LxYgxR8?xc2SEDvAKn4U3Y*#8&I5 z)Pllr_7n;e}70s0JsIsDjc_S&oQ2BkjHTDyfRiGpm7J(dDn zC@AaSAI|hYU26X;PRvEk2ewzpPR8k;+0(gOt!ryTgcdaw(zq{+6vJxFzhO~!iFRnX z$up1K`AX1pGonMd_C<`gEF~cGwiErFz&o;+q6`=-KR(AI)(`O@N@)S!Yw6#a>(PDba{T$Z{V3q5SZj=!r3uXPalur~Qy)6jmN1~@f7WyL{QxK6 zQ~GIsuH{2E_JEIW7=kZ3lD?icEyD`CMkrfn6<-tbbo@!~ta$~DboInPorMXX`J-df z6l)Yt&9J4!{k=T>>wX^;0OI{g%%WdIA&<~ z>T_P^OZ5X+_E{99fb^B6u+&>RWltj$t9+ zKN3=k^j|g8#LX%n)qMDugalBL%0LqJpnT~fn_|`|imPlY8(cdU1_XjemxI0?uvr<+ z!CLy~EOl-M=#SosRP$+s}X(y|&a}mu(b2-;3)Rg8(J_!!@@fZ1|_4 zl9n@x+)|?%IVHVPum*3FnAw5lsu^0J)qS7XNABClYZuXV9a!=r{7dYho%86~CafDRmQvNjUt_oMP z9D=$_R$FvDg18|0ud#|!MF{*LaLkP7P zL$0}s+?tU#`|huKFAi6bHnriPoK73esllFVKP~cF)rI~jzFW^cK~95pk`=zwn3(zj z&u@$`U6TFFeebQ--R} z^{8k`UM9GjMvN>ae)d^~dJEiCZBBS|a*q`G{ml{y;`%N-05h`5$-1U+y)@Ua^K!EC zYHFF$Ak!rbdiHt?d!84p*101p7p$+l@nKG_CRU^_K3#7iq-dGeb9?3c?Qt2GvDK&1 z&CXpR5Mf!>y1a&E;dK$F=UeKDmXKKHtM1r3qEJj;4EQbo)3vR#NaUX%?fkoVNHA96 z7Tw;I8PlutJlAnCX_Hx86dxr0L(Y)@{Trvjm0c*&BDN%;g660FCsUlR4JNcI$f*wc z!7`^D(+_3q52jJ$dD>2dUGk|ROQ`(e@~syRz0e+o<+%~d8=07ol6Qpe&^Oh1&wLL< zN#r2`^YbVcBXud#eceo3qRDPd`Qi74t8b6YT*1t;&zQ)U<1XfoTGt#%8gx@sD!@c7zmk`%YYmViLLR zbrH1r3{NRGB1b5HOY1DE74jk{&TP34F+3)w2K^#r6l1df?tgl=cT{%g|FuLxb@)VO zX%gi#%U83;vRR!CSI9P*cRm24cdgm->b*ZJi+joE*q+;nx_!ja4E+&(^t){Ke0Imq zDWY^_q?ju2@1xim`0A-}_KM8K$&e5m8IuYL?JNhtEnFZ6pdb$*svpog<76uysx03B zwnXdNdn*S){wULmsC_ren+yMu2Fv#Bovy#jSq{y^Z(wTg!l(XVFyD|ys@+RGiT=*A zkm|%mE9EyX$q{@2({vw>`Pbz_Sd%a`oKnzej$O41(C{F8{`ti%_GxffjqTg`6=TlU z@dWB+RHd9H2H_%p1OA<1yp=nSn`jDl_$Q9i7${_Ce{0i0DcbR;0)8W}<*VpLaENU* zJLn!Q*qAxh^Os%uG4ZOyX?Kb+f4E3#rKZDYV9%RR`%EYitLcD6L9s`AqVNZdNzn|T z&NSU1bK2Ff2pZO2`hU<5VVeJc3)=>eK}~AXcn6c$-nvUdjYCF z_O)D=8t3Gjr6twF`2Nh*Um>Fm>dMaCsN5LVKZLm=axPmw}1$!=6z8T%MJ z%_c>Y2*ZH}78>U^zY7xBIm3bxetT-@qf1TMys{`pjF;S{_G0F!D+hG~EU#@eb)YLX z6&=YE5Y`#OnkQ(2=N~#&Cxa)v>|co9b|gj15_)Kcn}eHzW=J>>@L4RZ$jc3=vjz!8 zcwA`YqE>__W_!F}e<1l%a=Da3@9G_gi5ySET(c~hV>D`ys@3#V;1(7CEiIAp8T!O9 zEh$tcB{OZ{kg%IoR^Gtk;;XCLlCq{d>QDAq9o{<5f7%@^{GWtSwXQ#iQNi?8BZht{ zLva`Q`ZSbIEbNRE-@`+}iAW&^d(GuZ5C#>@OJT8Q5|PS#ZpiD-x_87Jjb0S%@eE;cLETc2|E1i@?e7b~`>0}WqoC*!CH4RmSfyCqZ<$Q9*mw z-BrvTb2-B|ejM_EUn-x(=WQGEBVu3pe4q?+<^CES%Y5*OxyB1tJ$b#O%*Mq#SaoS_ z(|w=4i|2be1n)OTnl!R>wS6zOD`7 z?2=1qY|FJzXiXy;xj&zonB|8c^P>9Y^JKMb>5*0k64$Ts`24vZ>Y7K#;O98J43taE zhz?g4W3bT!p8A8Tm7NJOBOPGM?dsq(yJKZVh6T&ZU+y4FTb%0%3Z>H!B_zf(Cd zZi?{nHq6dZh8%T+hm>5;W?2%V2)f7a`T4!b175_bt~CUXq4{=gj2` z7$33Q*daSB6G>qHg1{1FErvQ`Vmg8V(JaQ|Uvg9Ydi0{*UOE0%jZ9RfIV^cLTtGi5 z4lkeF_Z_xJF9d(R8n?1@FSoO>)p}!tBjmF)J@;bA zea1>-DAHCI7in3jKFTP2Xa7D-ORIEwedVxGGdgrE0ssbESsqI11fr`v4an zB%z|{xgrsJ8KqHrryqx@(vCl=ig%FwPO3i_W+<;>^b9*L=5=sL|nji9kJkR#sM9E_~aTIx*AT=-KptYGm@&0MGZ3GxJdo`1Fki zK!mKW1_)gWv>-{n;V)<#XhAdm>2o&3%TAlxM{u26FZH2ISL4RO0JB_D4iCZ3# zmYXY<+rX+!=x1bX8Nb0@>I4#{p?CYPbrx~XcUKCxCG{ti3Abj`M0M+K0h~kvGHg8w zeR`1Bq<5`e3{4OUiv^pt{sz7q>L`LE#o=&y$cMX;8i4^P=#x>A$JCdPuEo!&aqruk z3I+Y0S-w3iGdM+ziVFLvz7l&i>DP-+<3|PeEEH*U@WtDdEN;U@N@gL@9Re5}3u|pW zCMEfnaUnTs^W?sAFV?6fh@N@8S5va%I^!9q3sfNUqrNT^cKi?4Hs8JWJPyBM)}lR) z6@4socA->kVKCASPBn`Z8rkHW{$#H#H??!nKrfyq!|&7gK3nZfG7LU?(BQHPFf3diTvsu8&iX*VOh0o3zN1U*T5MNtf6qI> zR9(TzkCc&iovHq!thtKrDQ=x1+DFe{!1s;zKA|v<$gy;kXEuu(K%?kwuCe z)bTvMEh}p4<7d?ODGnP&dd1g#Kc+3hs&#gLdvtKHFBxo+^*`?~E}IKEiwK%t?5yPk zdHB@L4kd{&=}jkeNoSCbvRzQWb0?SN!_ARR4V5v==67PV&QX3u@u~1-uXtlnFi|Bz zFHAv?AYpMQ@N1BbGN^pLJLW|Myu)sY*uboumv67mHR zA5@o0TZfyZoI6mpk=4Lhtl#O%nT3 zX;p-BH@~18YH=!q3YD}ZEstEV=1ZLgZ>rMTpeeo!t=S#Hz_yKw3a_AN# zL$93!E!@|XuAxQni)9I>Pjy7mx{?OBl0?Eya;A~YB8jYY5Ng7}egi?AU4ST^dAL07@a3EC?{+F@?d;sCsuNau0;M_6^8(htTDr=DK zg-3=>C3_-8!bq>ePmaxH`gVd<#g?(hxir!v8ca?Z7lPxLcvtBiJDh!U6&Q~$UE?q! zN9ivh*tag2LmeCRJFos)q+jBPtEDFwm~wT=m)b%Tug`eU=5YCfv{OY1+QXQjm-MtS zOSaV>U2=`okY1ZMuzBr}SkKS75aZCy1Cf)V%@3{^WEksyMBkNfwf1Rdw<4#}{G}SE zA$@kRx=Sq!DOMryNQOmgZ_({b3CHpZw6IDwen8)ee%mm;tXqF5usWK*x%4Va zmnP$CEAD{6&-dQh0=_i%DNQm^0!n6Gx46|;T4|Vow}IO*iYcUbLLfGjblmdw($9g8 z%@?`ZCu(htH!`fp>T7h0gvx2ja>SXX7vavTq9O7``>%=))B`+qpE;!oiT@&t5q|#} znbz@5?d=nB$RigL_`X?{aPzp_tX8 z;h7R&V`2Y55kH`!1-BNrmW5c2c@sNqyw&tPn52~L{(BaY_6sAaP#C~R|X3lMHR@ee8K;6P|&ZI z6oL%s#6Ax-`uEwoDUMf0xL)y8)K9el+97g$H|IO^l|r{tj8!RY%hLzVMs(IV*i?bg z&V`&nSM=;L6*UNxDd%ne>)4_Z>X7*ntE0GZk^@wIJRUHZxwy8QfSh4zoY;QLJoJuO zo$eY0xGf@iZOv~_6P}bTPW&i1ebliYc65+ed^TVM9(x+??lFJs`Vi&3!wwHs8619} zzshm?49D9946S$H&>nBu`J+X4m3~<4L+yNqGolAMPOy=Y6a0laEt6jB$8@P<1EHVG z8QCs{f2(7X2Qoeq#f20wEWnw{)}Hw7s=LDJNSALY{^JMe6U*@l-!C{aR=9$nhLXZN zn@i<*lHYs#3G!5EdwdXnMxC{$L8=sBn%45edbFg9N}(0eKZD~Jx^TJ zr)8T31!~b9WJ2BcU&H@21$oD&0=A7ejW?kS@46wO_gq?x5}!N z-GaS1gsj(HHiaza!kz};Ebk<}AB5z*vw1){T5}Y9EY9KX~&q-*YNXb)O6xoTu*pNEz)VfKcpPcRT zu|XFJT8uFUTENq0M5=M8j-#oVhyw&!cM!y~Yz15cgd@ZlY!@E=8Pky~dj@<97z9FaKaSjiQ&9^fM|m%D#}4UXD%V5rg76llhQbUBkT1!KjedAu3Zou8w-aW8s%a&;3)la zMp(V$TaMtPqkHfZJ+LAtX2uLo0KJP<# z4@akE)T=41>wQGTj2-(|??NceLG5>U2Cakh>1_+f&uK&DsLfNlkuI~FOQ_NUkpC8aW!*6Ek2rjVUc7kr&n1ewIC0^+x#{jA4;I9z7_oY1ALYQP5N@ z1H(cg*x|O@MfC2NE%q_yS#FZclE)8hI^t?Jw$&~M;7JxYmSrc{f|jakp<Z_+}gTq`iCmlwE;}eUU`P9-b^C+~J6q zda+;RTpP-Ecj-RU%com9)-I>#>D=cJ;bQ^65Ghj+o)t%NsCo2lZ-eY$K(1Cnjg<&X z|MXA_jxXeuh$(8+Pg+9b%Ao0yIE^eBYi4t4n6eGUHO0wZ0(RN{1amu&DY%ZCItjpC z1^(35*$K&I2!9Ve=>lR})r-RF2UZB2o-FBaps2Nqs3k&p;)7c);UlvXLz>^ zNm(&LjAbM%qKPEzY)QSQ8eIKOlpI8$q{;AUsVC@`i+=d+A_;}1P`uA%FB0HWgtS&X zy*++h!T2h@x7x>}((nK87M+?P}yn5qU4!f#o>6*JsJ;n-OlRbaiY4#o! zMNyV1i{NcX-7q$t+3N*N$#Pp;j3{3TaSvx;F{5UIiLAkT` zUGsw$Mosf$EgjKd&yVOSc*5u11+Xkybdx?kr93(IyMJQ2!3?vV*y&IF<=Py3IGI$%j2f zntK{EDdMqD8o`qE3wu@fhhiRt!rWCE?)y6T@V$VgD$MkLFX@dUc-jH8ECtr<% zcr`KPW)>G1?2V9?);YgJ)7ulWAY%K076~(}k^;Hi966&yQiUO)!U(OL`k7MaMHA@Q z0H)O-^w#X@yAnO(rKaGp#k_S|3#2p*;EMUxw%Hy2aOJKrycM4v;(-D zA08?n+#^PzNM$>yc60`=*&QCOib0HIV#;nTLT2Q1IjzL!$DZFPn2=6`IovjI>qt4=Jwxlp@ z?Af{4UeVAIW?@L+;^!=)eSb#@eWG;ABDv8_I|+TC%{|FpP2K4DztjYs(0}B$#+3W; z^J&nx`Sy4IBo&4-xZil^?u>FkRYNjMtG4B!x`=Qda?6G zU!6IHaurhCsjccr6Q7(Rue`86oRrvT=ko-!7Lezv{eFwA0pHve!T=rti+zHB)~Mo;jT8;JtdGoSI> zMLi9ICr98QhK0(cgQ=6otCjnnn1n|KJ0l%?Qe;QGdempvFcvIxb$qt@&J#x^*04M+ zXnmz8GmX9ldvYqaUV&w|q*C&SYy2FE?K2mtmo~X_V6>51RKSe{dS7CWGpp8Ei>uX5 zr&LKhd4ndt4EmgHdId!DvAmi$32F~LfACu4-?&$*NPHcLpxjewS|GUDYE4YECvJp) zc!m2vWr6kV#?s$evRpSdGeoW7-nwC~fpTR`#%NEfWuV%)C>f5~N zQc-(P1!p`r+t$xwZP(nfnB`qf2ZR z$7OAPjxWCj@;hPulipDg$jNwB&+=;$<#=1VmwKBCUY*{KWsk8C&!7zS7juWcl>uts=|UgL!(F z3F@;L&LZxYlA4ZBz$8SySA!2?)LIc73vHCftPuJ0Oyf!+R zQszi{BhLcgE23}omq=$$A*X{c6iYlOuqp`yatAYgx>5gA zIgYQ{pMx6l+fgnEA(_AdGD@R@+Z=t!prZCLilk>N--=mTWn;o&^@hn9&~WB=WGd9( zaj-|dxsWH(uyKxu_$dUZD?uBECsLAm^^LsnXSQ&fw74~IekQFmgpQm?l*ph92w(1y zZf=p)*8cfowwX$dHfqRN_AO3IT0wKM2(QNVs<3|MPXhd>yYdu?pW~wvA->oD^pG2J=$>?J+-pz!FxM ziajvVk%NEG2Wabx3ZGO2)=?w>0{9qOg03cNwe(ODlpJPk0vy^f+)KP93UXacqmiwI z5?W*tDJzE^iGfzBu7+By6grjNL8(b|OKbu>w`Oh{k`SJehKAq3#P}aBOFcT?BAY?k2!<4x?!e@Wr((a=CcEm+Ci<7C zDt-HU3K3Y~^T`M1%lsSt?zLP&%a1sXHG?$h!g*{E+JADzVdWE~^b<#9rWqb?6=N(WqW7IHt(`x6>Ev@M z&7KZhJ?tO-)d0-hwdL^aHij+t+j~I~vX{&pkzxZ>YGk#V&UZ@=^AU?ZnIDbO>;^>G zN1(#S+Fk7Km1^Yiu@;%?MzD$+i8YIQqT_){Jf8<;5q@Yu!Ox-0v`8RXOdkC{=6qK* z$L&R4QiH#D5sV08(F4BRx8y5rC2&YG+?UmEpGSfK8y(g>^nlOxjmwo-;I0*SSOCuA zP}YN&pSpv;7AbzjmD`-x>y8H7xWpA1jTkOWrsZLw*G?%Gs@T38rhOJ4N&-U(phabx zR1^7lT&OnkdSV)O!Kq0;6BRE86&w=vJr}PGI+c#Th?gEGSFGd!D6wTuPW-=1uv6?6 zIB@>K8*IM9cA5hOwEfm;R#X@gMb_K5x`j?w#`N;TUQ+ z97O3-{BruyYm6))kH<37wnf}ps%-|MR<9Jjlq-;a6dg*UfS_uTw34PB*nCTCBMy^H z>5W8!mIy?sNhG%>?Mqd*e^N4-ZQdM0y8@fm`;6a}+DFu_VEO{9v9i()8{Kx4mk;lP zyJxtxR)sKBPrK`3Ua+^Z*p1mtO-?%<0iVe5c`fcDzM2J4PY@;oBr$9L&4Oqh&V~G;7_Fg zq7>z)JI+6NQ~R2_HOo+1+?YfSuKAkRAuuR%E*Y+qE@VXNC&D|#4dyU>%V;(x4s;^Z zf*i0+p!TB4F?l_62)+=t0{bAv{ze}hnhKtHVQKutwrnJI zXj;UQELx+311RL7T6E$zvIsJAS!$h;alpG=x6yRu)ORXg|4 z&BeS^8A`%@lN^My0{z5bPnmtK{PWlG!!XI?lgX?SK-&;8$!{Y&{wQ=A_#HtM=ncf_u@@&?Op za4zkC5&vSrJ!}qNzc++UeeR7`7c!Fc>RIlYz;(*2de8WiwrPKBqQ)Ocj(w{RkLpEY zc)z%whaUaMOGqz&vKM!h%$$|ugFl%3?W$~DUR(C~bp2?SF^Bjx6Ug->(e4NC3Ofc) z-+Wn3qwBVS;n&h7$dmbFYqsM@{vKy<1mt%VbhBVGH>U_-Pi$DbkicB_4zJH#m z*EnBsr%iGiql1_kwJJ7}*{w`latPmH=~th)bx~dGwK%a!$s~}D{C-Ufy2zP5Gf-V{ zj`xt>JI(Gefdii9>TRKYrhgGstbc9R?vwjS$%4e480Qx^W(eLKf$P*@@MW(|vXFu_ zgH$pAX!lu-jK>Y0f)v*xvglX`R=Y=II8ici*pY8$A4vhrieGsy;;;owSsEWMdBuyC z;!5`wBw7`QXPg1l&E4A6#L`J?ZAZ%bB z3oKya7E<|hi9_g|G<+exu@0Y%-{A7gNt0~*76!NWss_aTxH7|~Y(#fEk~Pg@x;NpX zc_EPph3FPmLd5%$ykBte31HlgnXWJV`Q1}oVop0joRRCl%dV90sXmMO*;9o`kdok*xBv6$1O6*j^37byH8|c}xW<-iHrtSKN*} zZ0Nv*3hrr(?jAaFN>Rb%#b!=0q#Q+6-+_*!tPT*|M5MS_jNsBalEHDx1NJ>vUw#rr zdfp@8V8h<-tO)>Kk_j;ZNq}GV=f3OnxJ8Zp{;LOoaOICk*g@rbKLth?%dqfsp&rdN zy86%MsB#f|9CRCb5 zKDm#(nzi++1zCCSLo|=Syyslf;Y{PwYNDoI^PLrcCb$es!L6;SWpAuS&AXXoxBtMW zG7)D>@WLiE$B3hxhmsKZ4O=-czJd7u)Syi2EUThRMQPj}tklDh1$7T`a3})tvSEq8 z7lfXqCn-Y+5v8PgJ|+gAUQ(Am*mQ?2E{zj)v@y{2;q0|be7 zPyij}=d2T-Nf3BC4?J$TuqMu`+GNRnsviGx5QF%y+^cCJk8ch8Ef8USfY^U9#bHHQ z3c3GM2i>Nmf@M7>`mt=ioHU4p>1=6%_d_ogZtc`cU{QmQWOea`TGx)?>O<#T%)>dn zSWK-(C^v=SZj&DFoy25s#HRh%ZfYxG)rsoPPRZ_X2X1M zQ6~ocy_o4++Mq@G7YgW>D1*>CP#&i0iJ;Tf+~=0-6d5>1iiwU(EI{GxDgsLf0|F)A zyH=jik#a75EKuJ{%x(G3t|qHJtBss|iKQ}I!FJ^wGW#^L1=kAb>osl3OdGLU@F#|* z!wl=X%_vPvYWtm^H{3i7PcfK4RxWN~gqX2C^2R$5Xg(u0bNh%{D_m{wvt!K*5W}oP zFBzzYO1}uS`{Xt>=`-!Q!O5yAzJLE?73|kA{t9lRU=#!3qOgU898KXgafMuzOo^G9 z>2H?iboy?dxKZb0YIOs~GX+0EjkEFjqB`XGW4em%tlO1*a*&6|3f3JGKitG=&==ZV zWnzQvY7lOXUt9)qs)0vj1X5N0&KQr%1&$9ksf4+1w^SX4G*qtTW|4@Uhce$W1(^I> z5=XTNgela7y=2gPC^05}TS8U&M<~jmCDbrzeSkwXC)i}SUwaIK77;-HE-E=zckHBB z34+`)?Q(%fTA%KQadXh3zEIGO1xU$4e(R&6o7n{g@z z1;w6=`$ABitI-QP+D)+HiH`{(qnycT&a6G%^#tgz=@T!fOuOc>qkL(B+i zsA1N$dIP65S((6U*B1D~%HJ_$8jCqqRr1g#fIa|*N3DU?a_ecIbiqm$X`YNFGI9+bNqN4ZWvW_eJv4xuE!r6x)S{r-k0?kZl2K4<|GiX(oOHka9ORh#@bNM3X_V}J&k0C)tDGpa`T`Dv>B*V>+VO*1#2_CX_fLPb zcE^zA#=yI~N(If~<(ggWo|YG8V7#fmsT#VyDg1;wr5Ou~#HNjeQo9RlWEfel`JI6o z`p|GssrEf%!_w!B5|wjsyE6T6S3tjF6!lqQ@4=V0A86jCT=_)7_gLY;h5tZ8QU==F z47oZp(|Dmz3NbzH8q51<0m|^si7)>jW#E2Qg^r_SCx*VTu*@_x>xQ-8qEb^NVgO^7 z9JN)i2Dz{7K02BpWvJ&; zTE2r72F=vvZuz(8=xl~lLPbmu2p|eBaMa@eVHH;4)`BW=5B*>lfdj=vzeYm&O}cF+ z8s#ASO+LF8MtkI;7%i;}3%NOwW$m{Vj|G;BNj0tz_#DZ{hAU<*JXt*!nU;?;VBIyN zF6opqE*U4|bm1BBNWe$K768%Un%c-BZ!WJ>JT{*w3u{phZellHUI2|EuJs3!@orLj z4c6h@1IdD}JMJ^=)%I#fG5@6CpAdH-rEe@w^|z#k|SiTw;7YS2xm0MR5lxc^0*i(MJ4hq;!pUlxLmMzyI1%za{H zh~-2z8?RU-vsqIG5{v4MiXfmXjS@*tbR;1;eRv zRDfh07r~gm{F|yy^YN}Uc0z;1fR~K9YC4(Zy)$yzx)mIPf|*$ZgfXzy?t%m4-Q4%S zA+2~kZ!K2Ui?HnWE%1V@g6LGvA*EST_XYfKTYPN1<;1_PJGlPRSOf|$8eYYR&RE^z ze3#lq0D=HY5GCI6e-pwiMP6+aJDu_l=8G&YQX`6x;VRIVq*FM&>PaEosFvxF9|O`c zsz5_-XFFZBqGfqjSVp(crq?WWt7&Xz-c4qW8B8lo`nMJ^GOmionB<#M=Ot64QS&XY zjxFh@VIwX`IJOXG1%B59$ZqXK*};&D0jc+NLz2nzHQ$5mot@X%G8ql13_?DzEe`~ghMx=gh=cB4=ENS3l+g55M5yid*89e=S}TV_ zVTS3VZ^cV|22y!gf8RC%&oC=?#Lf$Y$~ny{nQq%n!aXZyG6&>Ws1f7Gjq$`vfc=Bj z&xK6xO`7f8flp{xUYB0<-yir0@%0V1ao`3`P;ue)E4jQ8F6amBWEP-9emqTcPw-bg zZ~QSGlTn_iB4NUOFAFZ<6Tj5lqHtaK!YQH}D8@Q^MR}u_)3@j`mZ%$?9jsa9#4sO- zGqLjFNn3ZyTevn9+29_Wh{XFC#N|i?LhNQ@L8s1#4(k>0Y0))D9zq*_n8@<-Y^sA~ zbx_egcJe%j0E3A#k2XO{8c580kTW&eet%?2s@v@HVj({m!cL?;K7kD z`t;0q2+xhzunEHKX+%RdVa~Raa^ckj3rG^3lw2;)pv)9hhV#-QDeVHUXAj#QNz5L7a%@J(Nj~o716fK zSeH&)Y&CDR9RE$IuAB(^tJz#bW6eyFdU_y^w_ZeY-wsMzrPyO zILs-2;PL$D`VN$xhcF2hZoLf?X=~5SV3>SVAf54MMluUj#3t`H@4`__{L(~};%*}b zuHE*}bs0bu?9aun#yq2EW(|S$mxsWPBw2Jwt5dM~MMRVtuib2a#3{5FC|r5neySS)-%oJCF>LuF1(Tiq!J*Y{-dd89Eqqy@Tc50{*Y;Xgw93E?5|HaW zn7hU!QKuYb}r?1**C;Jj8o(TmAj_-d#-9?M2?b_pt+pE*mLh z6Pucv>B3npZ=Ayz!he&rv+x1P5I6Oj`k$ORcx8rD0wuNL{-4-Tg!P!hv*HYsjxWi$ zQr%Hp03Ug7ot=ay-5&dRb?0Tm$FVZVdDtQ8dE2R13VwyUNyZGP2}T@a672kL%AVSwAK}chEH9*vmdm) zJnH80dVKYl<9nBGT$mSqWR38mUvHgHMHqi04|MR1ZM!rSC>jNO2`R*tsT?pJHjx$iQmp!rAz5Nv0m+5rVR5zYWjV;^E&H% zRxI-fjH;h=uJew?+-iTxiH$zXDEp8~mu=da^%L}s@+n&#DA9-fM4$cd$HOZ;V*Ve4 z@qPVxhJ>UVycy>=&7&L4}*55gG5)kFJ!9Bwp+LRTn{V|Qw=6*Fk(kzys2*xCUJT~MOW@NsjkBVxa>yTF4PAb zSWyM!*0=>e)H;Ncdw0)wG=MF;1lI0h3P&medwx7$H%3<-aEyq5nj5@io+kWv1XW;O zU*ELk2DzvofLEOV!+!gbydT(2|A+FOl*D=P$&%&<3ki?gwN5a-=R(9&KW-?R-ctjR zcJ0?0qVh2uabiCcIW=VbvBrAwv*Wl5aAL&(EELB+14Cqr9)sfV`o|2tfUmV;Dwjtb z#^Vb)1}0BGrH-0Z-ZCX+D64F0(dNyi#{3;_9KLIFGF70_69u}$Z$)-Te<#qu-Dkp` zo~9}7;KSVlg_<3=_!+)hQbYCQYi)T8^3x2Va3^PB1ZebF&B?tu1=@*ZNNfGZ$gpd9 zZOvO2a?2FBr6G||IMVNPJZOD88u16JG~t$$a`Drxbls5BOB&WGG`c7-dEucB!qT`u zn0o-mj!RQcsqcyaYp`m0YhaB(HjrkSZ@&eGUxdgaECPLFPz;ER>V(53Ee-!)yZ8|T zVp|l2FiNj@DQYz;2o*p3eZ(a}7&tUdqoK+#@eC9|7S;D_vU3Vn9fP0|FoY6On-(G= z;e7Fn=d^f`x?5iC8tadxpp-rJ;}@LtYg@?6KrkX$UZ~CsROJlurACq!*2W=1NFPBTQH?cl#%sh&rh2jo{ zLUBoOE5+R{Xt3h$DOTLwy|@G`?i6>2LUDIm++A*Z{&U~+wD*^_XU)u-1v#!>nC{Ya z{t0?ycHhOX*l?hPWx^e(M}UTJ&md=lSLL$ygz%iY%U?g3)DkQcP!JLMEqLQ~lhB35 zR;L`$itB~6E*o0wg6=cKr$O)<<@a89X8Q85Y`BdQyO4@zsse7!-fs3Qeb2zRqfP89 zkOZu4)VsGfsssOo?>+mzbr7<#P3RgMXe6JL$wa-}#0)vCp0E$&Rt_Fg8Yu1HHZ>y= zXr+K!+)fZVF>0E z&VT>tIVKn%Xzo{ypO`LSDMcc-d3kR*9uTzB@JV#Or+HWOBVm|HzBf!mrek-?YIqhy zr`UuvegEm7pkMkexuqf7Y`&b!JRI-&+AQ|+Z@P;Q;2neIk7w0N;kSma3AaQwYY`+e;lt0nFO&m3Rs{F&<^QfLg zcm}gcgtQS7G&49r!6l6_{g^GuDyJquo~bzrYbc2*<22^yq4GxRvC~tpOHsg^kIH;8 z-&V+;rd$E!RkgX$53Q%E$RD34+x|8vtiao6wv;d<4z6gJ`ML`h1Zl#+1~2=zDtGG% zhH83WMpjE$OWGZTe~8{t!&KzQs`wa{|5Rij7`RrTHX@0F^gAtuJse8_%5xF~;g zt1tYUVL1)TVvpLfGP`X~JQP(p@{exl@vwx2`6Pcs^~I5Eml=EW_7Op^mWvWp^Mpyx z*^gvVA&Kryy#DL1edp}HascC(Uj}7>*XP&CHBae5m$mtP&xe0Fe<%NbkLZb0D#u+W zpJE5D)j0YHZkhPXIH}|b0NnTb?o>U_={xK)f9}jkJ$y8#uVEgwt}&Ixr&Ud1NWf)` zXwM_czwN$yxH%;i3t;GhmmM=SKl8@@*kw4v_n3K#J|Wa<%Uuv|3M~O#%P1pqk-%~Q z$MLS10C(AyZf8EPl-E=qV`X}}Gf~1@?6q`N5t95%Z++~37tPgOk;zsZ=cP(f=i>ZC zu|!OX@uP$J?5hO?-}k?m7VnECV^ZpGmmU?{h{F34jT8?)8bMe(ZZ4ol%AYzlvC@koaIExh9|*=>ww5= zIWBr0BCx}|-(|TuTx~7U@zN0KzNb!Fcet9m9l`wqJdjf@;d5I-0+6~&b|+y{zlW)J zUEBnz>{9(6ruI_czCfbZW~^TjfPTwx#vCF^}+UoEN#fnn8O} zGCGRVlI-G3c&ALqW~ur2(p3&d_9vf_pX-Ql@ {oHnvU_|HVPS4)N%_uCAIzLS&q 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 +{% include JB/setup %} + +# Jupyter Interpreter for Apache Zeppelin + +
      + +## Overview + +Project [Jupyter](https://jupyter.org/) exists to develop open-source software, open-standards, and services for interactive computing across dozens of programming languages. +Zeppelin's Jupyter interpreter is a bridge/adapter between Zeppelin interpreter and Jupyter kernel. You can use any of jupyter kernel as long as you installed the necessary dependencies. + +## Configuration + +To run any Jupyter kernel in Zeppelin you first need to install the following prerequisite: + +* pip install jupyter-client +* pip install grpcio +* pip install protobuf + +Then you need install the jupyter kernel you want to use. In the following sections, we will talk about how to use the following 3 jupyter kernels in Zeppelin: + +* ipython +* ir +* julia + +## Jupyter Python kernel + +In order to use Jupyter Python kernel in Zeppelin, you need to install `ipykernel` first. + +```bash + +pip install ipykernel +``` + +Then you can run python code in Jupyter interpreter like following. + +```python + +%jupyter(kernel=python) + +%matplotlib inline +import matplotlib.pyplot as plt +plt.plot([1, 2, 3]) +``` + + + +## Jupyter R kernel + +In order to use [IRKernel](https://github.com/IRkernel/IRkernel), you need to first install `IRkernel` package in R. + +```r +install.packages('IRkernel') +IRkernel::installspec() # to register the kernel in the current R installation +``` + +Then you can run r code in Jupyter interpreter like following. + +```r +%jupyter(kernel=ir) + +library(ggplot2) +ggplot(mpg, aes(x = displ, y = hwy)) + + geom_point() +``` + + + + +## Jupyter Julia kernel + +In order to use Julia in Zeppelin, you first need to install [IJulia](https://github.com/JuliaLang/IJulia.jl) first + +```julia +using Pkg +Pkg.add("IJulia") + +``` + +Then you can run julia code in Jupyter interpreter like following. + +```julia + +%jupyter(kernel=julia-1.3) + +using Pkg +Pkg.add("Plots") +using Plots +plotly() # Choose the Plotly.jl backend for web interactivity +plot(rand(5,5),linewidth=2,title="My Plot") +Pkg.add("PyPlot") # Install a different backend +pyplot() # Switch to using the PyPlot.jl backend +plot(rand(5,5),linewidth=2,title="My Plot") +``` + + + + +## Use any other kernel + +For any other jupyter kernel, you can follow the below steps to use it in Zeppelin. + +1. Install the specified jupyter kernel. you can find all the available jupyter kernels [here](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels) +2. Find its kernel name by run the following command + ```bash + jupyter kernelspec list + ``` +3. Run the kernel as following + +```python + +%jupyter(kernel=kernel_name) + +code +``` \ No newline at end of file From 586e823e1630e054a6260b490a3322fcee366017 Mon Sep 17 00:00:00 2001 From: Muhammad Taufiq Date: Thu, 16 Jan 2020 14:11:25 +0000 Subject: [PATCH 30/32] [ZEPPELIN-4564] Changed path separator in Python interpreter to allow it to work on windows as well ### What is this PR for? Python Interpreter fails on Windows because of classpath issue ### What type of PR is it? Bug Fix ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-4564# THIS SOFTWARE IS CONTRIBUTED SUBJECT TO THE TERMS OF THE APACHE SOFTWARE FOUNDATION SOFTWARE GRANT AND CORPORATE CONTRIBUTOR LICENSE AGREEMENT VERSION R190612. THIS SOFTWARE IS LICENSED 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 AND ANY WARRANTY OF NON-INFRINGEMENT, 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. THIS SOFTWARE MAY BE REDISTRIBUTED TO OTHERS ONLY BY EFFECTIVELY USING THIS OR ANOTHER EQUIVALENT DISCLAIMER IN ADDITION TO ANY OTHER REQUIRED LICENSE TERMS. Author: Muhammad Taufiq Closes #3604 from Muhammad-ms/zeppelin9_file_separator and squashes the following commits: a09b6463a [Muhammad Taufiq] Changed path separator to allow it to work on windows as well --- .../main/java/org/apache/zeppelin/python/PythonInterpreter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java index 4d8a4b726a2..e4ea7321672 100644 --- a/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java +++ b/python/src/main/java/org/apache/zeppelin/python/PythonInterpreter.java @@ -219,7 +219,7 @@ private void appendToPythonPath(Map env, String path) { if (!env.containsKey("PYTHONPATH")) { env.put("PYTHONPATH", path); } else { - env.put("PYTHONPATH", env.get("PYTHONPATH") + ":" + path); + env.put("PYTHONPATH", env.get("PYTHONPATH") + File.pathSeparator + path); } } From 6a122cceeb7d7804e0fa2ea2ce5082cfcf9c215e Mon Sep 17 00:00:00 2001 From: vthinkxie Date: Thu, 16 Jan 2020 12:47:00 +0800 Subject: [PATCH 31/32] [ZEPPELIN-4552] Support scroll to the paragraph specified by the url param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Support scroll to the paragraph specified by the url param ### What type of PR is it? [Feature] ### Todos * [ ] - Task ### What is the Jira issue? [ZEPPELIN-4552] ### How should this be tested? https://travis-ci.org/vthinkxie/zeppelin/builds/637914933 ### Screenshots (if appropriate) 截屏2020-01-19下午4 01 47 ### Questions: * Does the licenses files need update? no * Is there breaking changes for older versions? no * Does this needs documentation? no Author: vthinkxie Closes #3601 from vthinkxie/ZEPPELIN-4552 and squashes the following commits: 4922e93a3 [vthinkxie] [ZEPPELIN-4552] Support scroll to the paragraph specified by the url param --- .../result-item/result-item.component.html | 2 +- .../result-item/result-item.component.ts | 23 ++++++++++---- .../notebook/notebook.component.html | 1 + .../workspace/notebook/notebook.component.ts | 17 +++++++++- .../notebook/paragraph/paragraph.component.ts | 31 +++++++++++++------ 5 files changed, 57 insertions(+), 17 deletions(-) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html index dcd78dc9180..14d6ee6bacc 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html @@ -12,7 +12,7 @@ -
      {{displayName}} + {{displayName}} data.get('paragraph')) + ) + .subscribe(id => { + this.onParagraphSelect(id); + this.onParagraphScrolled(id); + }); this.activatedRoute.params .pipe( takeUntil(this.destroy$), diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index ad9691e9ab6..3afdea13f6d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -11,6 +11,7 @@ */ import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -62,7 +63,7 @@ type Mode = 'edit' | 'command'; }, changeDetection: ChangeDetectionStrategy.OnPush }) -export class NotebookParagraphComponent extends ParagraphBase implements OnInit, OnChanges, OnDestroy { +export class NotebookParagraphComponent extends ParagraphBase implements OnInit, OnChanges, OnDestroy, AfterViewInit { @ViewChild(NotebookParagraphCodeEditorComponent, { static: false }) notebookParagraphCodeEditorComponent: NotebookParagraphCodeEditorComponent; @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents: QueryList< @@ -73,6 +74,7 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, @Input() looknfeel: string; @Input() revisionView: boolean; @Input() select: boolean = false; + @Input() scrolled: boolean = false; @Input() index: number = -1; @Input() viewOnly: boolean; @Input() last: boolean; @@ -608,25 +610,36 @@ export class NotebookParagraphComponent extends ParagraphBase implements OnInit, }); } + scrollIfNeeded(): void { + if (this.scrolled && this.host.nativeElement) { + setTimeout(() => { + this.host.nativeElement.scrollIntoView(); + }); + } + } ngOnChanges(changes: SimpleChanges): void { - const { index, select } = changes; + const { index, select, scrolled } = changes; if ( (index && index.currentValue !== index.previousValue && this.select) || (select && select.currentValue === true && select.previousValue !== true) ) { - if (this.host.nativeElement) { - setTimeout(() => { - if (this.mode === 'command') { - (this.host.nativeElement as HTMLElement).focus(); - } - }); - } + setTimeout(() => { + if (this.mode === 'command' && this.host.nativeElement) { + (this.host.nativeElement as HTMLElement).focus(); + } + }); + } + if (scrolled) { + this.scrollIfNeeded(); } } getElement(): HTMLElement { return this.host && this.host.nativeElement; } + ngAfterViewInit(): void { + this.scrollIfNeeded(); + } ngOnDestroy(): void { super.ngOnDestroy(); From ceff31a7ef431757f223d89861356de0ae7b61d7 Mon Sep 17 00:00:00 2001 From: vthinkxie Date: Thu, 16 Jan 2020 13:10:03 +0800 Subject: [PATCH 32/32] [ZEPPELIN-4558] fix note list is not sorted by name in new web ui ### What is this PR for? fix note list is not sorted by name in new web ui ### What type of PR is it? [Bug Fix] ### Todos * [ ] - Task ### What is the Jira issue? [ZEPPELIN-4558] ### How should this be tested? https://travis-ci.org/vthinkxie/zeppelin/builds/637915102 ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? no * Is there breaking changes for older versions? no * Does this needs documentation? no Author: vthinkxie Closes #3602 from vthinkxie/ZEPPELIN-4558 and squashes the following commits: a4d547205 [vthinkxie] [ZEPPELIN-4558] fix note list is not sorted by name in new web ui --- .../src/app/interfaces/node-list.ts | 1 + .../share/node-list/node-list.component.ts | 40 +++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/zeppelin-web-angular/src/app/interfaces/node-list.ts b/zeppelin-web-angular/src/app/interfaces/node-list.ts index 3330e03aa75..55331a9e740 100644 --- a/zeppelin-web-angular/src/app/interfaces/node-list.ts +++ b/zeppelin-web-angular/src/app/interfaces/node-list.ts @@ -27,6 +27,7 @@ export interface NodeItem { expanded?: boolean; children?: NodeItem[]; isTrash: boolean; + nodeType?: string; path?: string; } diff --git a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts index 5d9abb4d89e..23a70c7f508 100644 --- a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts +++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts @@ -10,7 +10,8 @@ * limitations under the License. */ -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, OnInit } from '@angular/core'; +import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces'; import { NzTreeNode } from 'ng-zorro-antd/core'; import { NzModalService } from 'ng-zorro-antd/modal'; @@ -96,15 +97,46 @@ export class NodeListComponent extends MessageListenersManager implements OnInit @MessageListener(OP.NOTES_INFO) getNotes(data: MessageReceiveDataTypeMap[OP.NOTES_INFO]) { this.noteListService.setNotes(data.notes); - this.nodes = this.noteListService.notes.root.children.map(item => { - return { ...item, key: item.id }; - }); + this.nodes = this.noteListService.notes.root.children + .sort((v1, v2) => this.noteComparator(v1, v2)) + .map(item => { + return { ...item, key: item.id }; + }); this.cdr.markForCheck(); } + getNoteName(note) { + if (note.title === undefined || note.title.trim() === '') { + return 'Note ' + note.id; + } else { + return note.title; + } + } + + noteComparator(v1, v2) { + const note1 = v1; + const note2 = v2; + if (note1.id === this.TRASH_FOLDER_ID) { + return 1; + } + if (note2.id === this.TRASH_FOLDER_ID) { + return -1; + } + if (note1.children === undefined && note2.children !== undefined) { + return 1; + } + if (note1.children !== undefined && note2.children === undefined) { + return -1; + } + const noteName1 = this.getNoteName(note1); + const noteName2 = this.getNoteName(note2); + return noteName1.localeCompare(noteName2); + } + constructor( private noteListService: NoteListService, public messageService: MessageService, + @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string, private nzModalService: NzModalService, private noteActionService: NoteActionService, private cdr: ChangeDetectorRef