diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..a4bcf180 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +gui/node_modules +.git +# exclude all of the `build` directory except for our bin and gui +# directories since they need to be in the image +build +!build/bin +!build/gui diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1ed96231 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/build +dist +tmp +out-tsc +gui/src/environments/environment.prod.ts + +# dependencies +node_modules + + +# 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 + +# Version File +VERSION +# But don't ignore "version" folders like in k8s apis in vendor +!VERSION/ + +# SSL certificates (should be generated by end deployment) +deploy/scripts/ssl +*.srl + +# Golang testing files +*.test +.cover/ + +# python +__pycache__ \ No newline at end of file diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 00000000..d3299746 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,680 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:2fd83c8c2b1ff53fd7c4376a63c3a2f31e002e9296df9d7f150b07da524de88d" + name = "github.com/briandowns/spinner" + packages = ["."] + pruneopts = "UT" + revision = "dd69c579ff204842e8962816987f838e2c2c18d8" + version = "1.4" + +[[projects]] + digest = "1:a571648c5f1a3f20fa405d1cf924b941c5bb236ea6d0565a63c0994e38dd8f82" + name = "github.com/caarlos0/env" + packages = ["."] + pruneopts = "UT" + revision = "518fcfb943252f77846f92ce5794086d9cb4a1b5" + version = "v3.5.0" + +[[projects]] + digest = "1:f6e5e1bc64c2908167e6aa9a1fe0c084d515132a1c63ad5b6c84036aa06dc0c1" + name = "github.com/coreos/go-oidc" + packages = ["."] + pruneopts = "UT" + revision = "1180514eaf4d9f38d0d19eef639a1d695e066e72" + version = "v2.0.0" + +[[projects]] + digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec" + name = "github.com/davecgh/go-spew" + packages = ["spew"] + pruneopts = "UT" + revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" + version = "v1.1.1" + +[[projects]] + digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55" + name = "github.com/dgrijalva/jwt-go" + packages = ["."] + pruneopts = "UT" + revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" + version = "v3.2.0" + +[[projects]] + digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a" + name = "github.com/fatih/color" + packages = ["."] + pruneopts = "UT" + revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4" + version = "v1.7.0" + +[[projects]] + digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" + name = "github.com/fsnotify/fsnotify" + packages = ["."] + pruneopts = "UT" + revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" + version = "v1.4.7" + +[[projects]] + digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda" + name = "github.com/ghodss/yaml" + packages = ["."] + pruneopts = "UT" + revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" + version = "v1.0.0" + +[[projects]] + digest = "1:41206f4d0410803e64cfb203f665330c3183988408cb532b56305a816a87bd99" + name = "github.com/go-resty/resty" + packages = ["."] + pruneopts = "UT" + revision = "fa5875c0caa5c260ab78acec5a244215a730247f" + version = "v1.12.0" + +[[projects]] + digest = "1:4d02824a56d268f74a6b6fdd944b20b58a77c3d70e81008b3ee0c4f1a6777340" + name = "github.com/gogo/protobuf" + packages = [ + "proto", + "sortkeys", + ] + pruneopts = "UT" + revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c" + version = "v1.2.1" + +[[projects]] + branch = "master" + digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467" + name = "github.com/golang/glog" + packages = ["."] + pruneopts = "UT" + revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998" + +[[projects]] + digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf" + name = "github.com/golang/protobuf" + packages = [ + "proto", + "ptypes", + "ptypes/any", + "ptypes/duration", + "ptypes/timestamp", + ] + pruneopts = "UT" + revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" + version = "v1.2.0" + +[[projects]] + branch = "master" + digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb" + name = "github.com/google/gofuzz" + packages = ["."] + pruneopts = "UT" + revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" + +[[projects]] + digest = "1:65c4414eeb350c47b8de71110150d0ea8a281835b1f386eacaa3ad7325929c21" + name = "github.com/googleapis/gnostic" + packages = [ + "OpenAPIv2", + "compiler", + "extensions", + ] + pruneopts = "UT" + revision = "7c663266750e7d82587642f65e60bc4083f1f84e" + version = "v0.2.0" + +[[projects]] + digest = "1:ca59b1175189b3f0e9f1793d2c350114be36eaabbe5b9f554b35edee1de50aea" + name = "github.com/gorilla/mux" + packages = ["."] + pruneopts = "UT" + revision = "a7962380ca08b5a188038c69871b8d3fbdf31e89" + version = "v1.7.0" + +[[projects]] + digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" + name = "github.com/hashicorp/hcl" + packages = [ + ".", + "hcl/ast", + "hcl/parser", + "hcl/printer", + "hcl/scanner", + "hcl/strconv", + "hcl/token", + "json/parser", + "json/scanner", + "json/token", + ] + pruneopts = "UT" + revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241" + version = "v1.0.0" + +[[projects]] + digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" + name = "github.com/inconshreveable/mousetrap" + packages = ["."] + pruneopts = "UT" + revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" + version = "v1.0" + +[[projects]] + digest = "1:f5a2051c55d05548d2d4fd23d244027b59fbd943217df8aa3b5e170ac2fd6e1b" + name = "github.com/json-iterator/go" + packages = ["."] + pruneopts = "UT" + revision = "0ff49de124c6f76f8494e194af75bde0f1a49a29" + version = "v1.1.6" + +[[projects]] + digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" + version = "v1.0.1" + +[[projects]] + digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7" + name = "github.com/magiconair/properties" + packages = ["."] + pruneopts = "UT" + revision = "c2353362d570a7bfa228149c62842019201cfb71" + version = "v1.8.0" + +[[projects]] + branch = "master" + digest = "1:aa3d8d42865c42626b5c1add193692d045b3188b1479f0a0a88690d21fe20083" + name = "github.com/mailru/easyjson" + packages = [ + ".", + "buffer", + "jlexer", + "jwriter", + ] + pruneopts = "UT" + revision = "60711f1a8329503b04e1c88535f419d0bb440bff" + +[[projects]] + digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67" + name = "github.com/mattn/go-colorable" + packages = ["."] + pruneopts = "UT" + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + +[[projects]] + digest = "1:3bb9c8451d199650bfd303e0068d86f135952fead374ad87c09a9b8a2cc4bd7c" + name = "github.com/mattn/go-isatty" + packages = ["."] + pruneopts = "UT" + revision = "369ecd8cea9851e459abb67eb171853e3986591e" + version = "v0.0.6" + +[[projects]] + digest = "1:0356f3312c9bd1cbeda81505b7fd437501d8e778ab66998ef69f00d7f9b3a0d7" + name = "github.com/mattn/go-runewidth" + packages = ["."] + pruneopts = "UT" + revision = "3ee7d812e62a0804a7d0a324e0249ca2db3476d3" + version = "v0.0.4" + +[[projects]] + digest = "1:53bc4cd4914cd7cd52139990d5170d6dc99067ae31c56530621b18b35fc30318" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + pruneopts = "UT" + revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe" + version = "v1.1.2" + +[[projects]] + digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563" + name = "github.com/modern-go/concurrent" + packages = ["."] + pruneopts = "UT" + revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" + version = "1.0.3" + +[[projects]] + digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855" + name = "github.com/modern-go/reflect2" + packages = ["."] + pruneopts = "UT" + revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" + version = "1.0.1" + +[[projects]] + digest = "1:abcdbf03ca6ca13d3697e2186edc1f33863bbdac2b3a44dfa39015e8903f7409" + name = "github.com/olekukonko/tablewriter" + packages = ["."] + pruneopts = "UT" + revision = "e6d60cf7ba1f42d86d54cdf5508611c4aafb3970" + version = "v0.0.1" + +[[projects]] + digest = "1:d1da5ee400cc3c39cf7d920c2db4b04d9407e24a917bf8b99a183aa024081871" + name = "github.com/olivere/elastic" + packages = [ + ".", + "config", + "uritemplates", + ] + pruneopts = "UT" + revision = "407a1d940dcc89e279c579eb393d0bdde8fd9ac4" + version = "v6.2.16" + +[[projects]] + digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e" + name = "github.com/pelletier/go-toml" + packages = ["."] + pruneopts = "UT" + revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" + version = "v1.2.0" + +[[projects]] + digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" + name = "github.com/pkg/errors" + packages = ["."] + pruneopts = "UT" + revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" + version = "v0.8.1" + +[[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" + name = "github.com/pmezard/go-difflib" + packages = ["difflib"] + pruneopts = "UT" + revision = "792786c7400a136282c1664665ae0a8db921c6c2" + version = "v1.0.0" + +[[projects]] + branch = "master" + digest = "1:bd9efe4e0b0f768302a1e2f0c22458149278de533e521206e5ddc71848c269a0" + name = "github.com/pquerna/cachecontrol" + packages = [ + ".", + "cacheobject", + ] + pruneopts = "UT" + revision = "1555304b9b35fdd2b425bccf1a5613677705e7d0" + +[[projects]] + digest = "1:87c2e02fb01c27060ccc5ba7c5a407cc91147726f8f40b70cceeedbc52b1f3a8" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "e1e72e9de974bd926e5c56f83753fba2df402ce5" + version = "v1.3.0" + +[[projects]] + digest = "1:3e39bafd6c2f4bf3c76c3bfd16a2e09e016510ad5db90dc02b88e2f565d6d595" + name = "github.com/spf13/afero" + packages = [ + ".", + "mem", + ] + pruneopts = "UT" + revision = "f4711e4db9e9a1d3887343acb72b2bbfc2f686f5" + version = "v1.2.1" + +[[projects]] + digest = "1:08d65904057412fc0270fc4812a1c90c594186819243160dc779a402d4b6d0bc" + name = "github.com/spf13/cast" + packages = ["."] + pruneopts = "UT" + revision = "8c9545af88b134710ab1cd196795e7f2388358d7" + version = "v1.3.0" + +[[projects]] + digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939" + name = "github.com/spf13/cobra" + packages = ["."] + pruneopts = "UT" + revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" + version = "v0.0.3" + +[[projects]] + digest = "1:68ea4e23713989dc20b1bded5d9da2c5f9be14ff9885beef481848edd18c26cb" + name = "github.com/spf13/jwalterweatherman" + packages = ["."] + pruneopts = "UT" + revision = "4a4406e478ca629068e7768fc33f3f044173c0a6" + version = "v1.0.0" + +[[projects]] + digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2" + name = "github.com/spf13/pflag" + packages = ["."] + pruneopts = "UT" + revision = "298182f68c66c05229eb03ac171abe6e309ee79a" + version = "v1.0.3" + +[[projects]] + digest = "1:de37e343c64582d7026bf8ab6ac5b22a72eac54f3a57020db31524affed9f423" + name = "github.com/spf13/viper" + packages = ["."] + pruneopts = "UT" + revision = "6d33b5a963d922d182c91e8a1c88d81fd150cfd4" + version = "v1.3.1" + +[[projects]] + digest = "1:ac83cf90d08b63ad5f7e020ef480d319ae890c208f8524622a2f3136e2686b02" + name = "github.com/stretchr/objx" + packages = ["."] + pruneopts = "UT" + revision = "477a77ecc69700c7cdeb1fa9e129548e1c1c393c" + version = "v0.1.1" + +[[projects]] + digest = "1:0bcc464dabcfad5393daf87c3f8142911d0f6c52569b837e91a1c15e890265f3" + name = "github.com/stretchr/testify" + packages = [ + "assert", + "mock", + ] + pruneopts = "UT" + revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" + version = "v1.3.0" + +[[projects]] + branch = "master" + digest = "1:fb961be99914b3b93d599cabeaec91736f662e3f706b894668fcd23c0d9aafd7" + name = "golang.org/x/crypto" + packages = [ + "ed25519", + "ed25519/internal/edwards25519", + "pbkdf2", + "ssh/terminal", + ] + pruneopts = "UT" + revision = "74369b46fc6756741c016591724fd1cb8e26845f" + +[[projects]] + branch = "master" + digest = "1:95b9483e6e767e94bc795c20367957851e0b422a1693792d3b8cf164498d17ff" + name = "golang.org/x/net" + packages = [ + "context", + "context/ctxhttp", + "http/httpguts", + "http2", + "http2/hpack", + "idna", + "publicsuffix", + ] + pruneopts = "UT" + revision = "3a22650c66bd7f4fb6d1e8072ffd7b75c8a27898" + +[[projects]] + branch = "master" + digest = "1:c664d4451770ebc9ab63d54bccb9e4f2c6106cde7e566ea02889930b836c7d4c" + name = "golang.org/x/oauth2" + packages = [ + ".", + "internal", + ] + pruneopts = "UT" + revision = "3e8b2be1363542a95c52ea0796d4a40dacfb5b95" + +[[projects]] + branch = "master" + digest = "1:0d703f14f9bbbe1070ff0ce86d749dcbc9d68fb0ae554252c09bd4bb37a072e7" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "983097b1a8a340cd1cc7df17d735154d89e10b1a" + +[[projects]] + digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18" + name = "golang.org/x/text" + packages = [ + "collate", + "collate/build", + "internal/colltab", + "internal/gen", + "internal/tag", + "internal/triegen", + "internal/ucd", + "language", + "secure/bidirule", + "transform", + "unicode/bidi", + "unicode/cldr", + "unicode/norm", + "unicode/rangetable", + ] + pruneopts = "UT" + revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" + version = "v0.3.0" + +[[projects]] + branch = "master" + digest = "1:9fdc2b55e8e0fafe4b41884091e51e77344f7dc511c5acedcfd98200003bff90" + name = "golang.org/x/time" + packages = ["rate"] + pruneopts = "UT" + revision = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef" + +[[projects]] + digest = "1:6f3bd49ddf2e104e52062774d797714371fac1b8bddfd8e124ce78e6b2264a10" + name = "google.golang.org/appengine" + packages = [ + "internal", + "internal/base", + "internal/datastore", + "internal/log", + "internal/remote_api", + "internal/urlfetch", + "urlfetch", + ] + pruneopts = "UT" + revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" + version = "v1.4.0" + +[[projects]] + digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" + name = "gopkg.in/inf.v0" + packages = ["."] + pruneopts = "UT" + revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" + version = "v0.9.1" + +[[projects]] + branch = "v2" + digest = "1:2642fd0b6900c77247d61d80cf2eb59a374ef4ffc2d25a1b95b87dc355b2894e" + name = "gopkg.in/mgo.v2" + packages = [ + "bson", + "internal/json", + ] + pruneopts = "UT" + revision = "9856a29383ce1c59f308dd1cf0363a79b5bef6b5" + +[[projects]] + digest = "1:377f8ccfbf9d7ff3997ea7454b894de46cd1d9fe6ec1e724c93ad59eb716c5c0" + name = "gopkg.in/square/go-jose.v2" + packages = [ + ".", + "cipher", + "json", + ] + pruneopts = "UT" + revision = "e94fb177d3668d35ab39c61cbb2f311550557e83" + version = "v2.2.2" + +[[projects]] + digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" + name = "gopkg.in/yaml.v2" + packages = ["."] + pruneopts = "UT" + revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" + version = "v2.2.2" + +[[projects]] + digest = "1:9e4dd60b5b4fda39e18da7879b26f8f44f47fa7fbc4f465eaeafd929bce54803" + name = "k8s.io/api" + packages = [ + "admissionregistration/v1alpha1", + "admissionregistration/v1beta1", + "apps/v1", + "apps/v1beta1", + "apps/v1beta2", + "authentication/v1", + "authentication/v1beta1", + "authorization/v1", + "authorization/v1beta1", + "autoscaling/v1", + "autoscaling/v2beta1", + "batch/v1", + "batch/v1beta1", + "batch/v2alpha1", + "certificates/v1beta1", + "core/v1", + "events/v1beta1", + "extensions/v1beta1", + "networking/v1", + "policy/v1beta1", + "rbac/v1", + "rbac/v1alpha1", + "rbac/v1beta1", + "scheduling/v1alpha1", + "settings/v1alpha1", + "storage/v1", + "storage/v1alpha1", + "storage/v1beta1", + ] + pruneopts = "UT" + revision = "0f11257a8a25954878633ebdc9841c67d8f83bdb" + version = "kubernetes-1.10.7" + +[[projects]] + digest = "1:bc7920d9796bd371e092d379b27b6b9bd3b50d135260cbdc10512dde51aec449" + name = "k8s.io/apimachinery" + packages = [ + "pkg/api/errors", + "pkg/api/meta", + "pkg/api/resource", + "pkg/apis/meta/v1", + "pkg/apis/meta/v1/unstructured", + "pkg/apis/meta/v1beta1", + "pkg/conversion", + "pkg/conversion/queryparams", + "pkg/fields", + "pkg/labels", + "pkg/runtime", + "pkg/runtime/schema", + "pkg/runtime/serializer", + "pkg/runtime/serializer/json", + "pkg/runtime/serializer/protobuf", + "pkg/runtime/serializer/recognizer", + "pkg/runtime/serializer/streaming", + "pkg/runtime/serializer/versioning", + "pkg/selection", + "pkg/types", + "pkg/util/clock", + "pkg/util/errors", + "pkg/util/framer", + "pkg/util/intstr", + "pkg/util/json", + "pkg/util/net", + "pkg/util/runtime", + "pkg/util/sets", + "pkg/util/validation", + "pkg/util/validation/field", + "pkg/util/wait", + "pkg/util/yaml", + "pkg/version", + "pkg/watch", + "third_party/forked/golang/reflect", + ] + pruneopts = "UT" + revision = "e386b2658ed20923da8cc9250e552f082899a1ee" + version = "kubernetes-1.10.7" + +[[projects]] + digest = "1:668e3c4436108728b89f3c349a7932ffc2c3436c23e202f99924479889e01fa5" + name = "k8s.io/client-go" + packages = [ + "discovery", + "kubernetes", + "kubernetes/scheme", + "kubernetes/typed/admissionregistration/v1alpha1", + "kubernetes/typed/admissionregistration/v1beta1", + "kubernetes/typed/apps/v1", + "kubernetes/typed/apps/v1beta1", + "kubernetes/typed/apps/v1beta2", + "kubernetes/typed/authentication/v1", + "kubernetes/typed/authentication/v1beta1", + "kubernetes/typed/authorization/v1", + "kubernetes/typed/authorization/v1beta1", + "kubernetes/typed/autoscaling/v1", + "kubernetes/typed/autoscaling/v2beta1", + "kubernetes/typed/batch/v1", + "kubernetes/typed/batch/v1beta1", + "kubernetes/typed/batch/v2alpha1", + "kubernetes/typed/certificates/v1beta1", + "kubernetes/typed/core/v1", + "kubernetes/typed/events/v1beta1", + "kubernetes/typed/extensions/v1beta1", + "kubernetes/typed/networking/v1", + "kubernetes/typed/policy/v1beta1", + "kubernetes/typed/rbac/v1", + "kubernetes/typed/rbac/v1alpha1", + "kubernetes/typed/rbac/v1beta1", + "kubernetes/typed/scheduling/v1alpha1", + "kubernetes/typed/settings/v1alpha1", + "kubernetes/typed/storage/v1", + "kubernetes/typed/storage/v1alpha1", + "kubernetes/typed/storage/v1beta1", + "pkg/apis/clientauthentication", + "pkg/apis/clientauthentication/v1alpha1", + "pkg/version", + "plugin/pkg/client/auth/exec", + "rest", + "rest/watch", + "tools/clientcmd/api", + "tools/metrics", + "tools/reference", + "transport", + "util/cert", + "util/flowcontrol", + "util/integer", + ] + pruneopts = "UT" + revision = "23781f4d6632d88e869066eaebb743857aa1ef9b" + version = "v7.0.0" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/briandowns/spinner", + "github.com/caarlos0/env", + "github.com/coreos/go-oidc", + "github.com/dgrijalva/jwt-go", + "github.com/go-resty/resty", + "github.com/gorilla/mux", + "github.com/olekukonko/tablewriter", + "github.com/olivere/elastic", + "github.com/pkg/errors", + "github.com/sirupsen/logrus", + "github.com/spf13/cobra", + "github.com/spf13/viper", + "github.com/stretchr/testify/assert", + "github.com/stretchr/testify/mock", + "golang.org/x/oauth2", + "gopkg.in/mgo.v2/bson", + "k8s.io/api/core/v1", + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/client-go/kubernetes", + "k8s.io/client-go/kubernetes/typed/core/v1", + "k8s.io/client-go/rest", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 00000000..7b35a488 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,82 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/gorilla/mux" + version = "=1.7.0" + +[[constraint]] + name = "github.com/olivere/elastic" + version = "=6.2.16" + +[[constraint]] + name = "github.com/sirupsen/logrus" + version = "=1.3.0" + +[[constraint]] + name = "github.com/spf13/cobra" + version = "=0.0.3" + +[[constraint]] + name = "github.com/spf13/viper" + version = "=v1.3.1" + +[prune] + go-tests = true + unused-packages = true + +[[constraint]] + name = "github.com/dgrijalva/jwt-go" + version = "=3.2.0" + +[[override]] + name = "github.com/stretchr/testify" + version = "=1.3.0" + +[[constraint]] + name = "github.com/briandowns/spinner" + version = "=1.4.0" + +[[constraint]] + name = "github.com/olekukonko/tablewriter" + version = "=0.0.1" + +[[override]] + name = "k8s.io/api" + version = "kubernetes-1.10.7" + +[[override]] + name = "k8s.io/apimachinery" + version = "kubernetes-1.10.7" + +[[override]] + name = "k8s.io/client-go" + version = "7.0.0" + +[[constraint]] + name = "github.com/go-resty/resty" + version = "=1.12.0" diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..b052c9c3 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,116 @@ +// Use this crazy thing instead of 'checkout scm' so we can get tags fetched... +def checkoutSCMWithTags() { + checkout([ + $class: 'GitSCM', + branches: scm.branches, + doGenerateSubmoduleConfigurations: scm.doGenerateSubmoduleConfigurations, + extensions: [ + [$class: 'CloneOption', noTags: false, shallow: false, depth: 0, reference: ''], + [$class: 'CleanBeforeCheckout'] + ], + userRemoteConfigs: scm.userRemoteConfigs + ]) +} + +def runStageWithTimeout(String stageName, int timeoutMinutes, Closure stageToRun) { + stage(stageName) { + ansiColor('xterm') { + timeout(timeoutMinutes) { + stageToRun() + } + } + } +} + +properties( + [ + [$class: 'BuildDiscarderProperty', + strategy: [ + $class: 'LogRotator', + artifactDaysToKeepStr: '', + artifactNumToKeepStr: '10', + daysToKeepStr: '', + numToKeepStr: '10'] + ] + ] +) + +node('pure1-unplugged') { + try { + // Always checkout the repo before running any stages + checkoutSCMWithTags() + parallel "Build + Test Server Binaries (Golang)": { + runStageWithTimeout('Pull Go Builder Image', 10) { + sh 'make pull-go-image' + } + + runStageWithTimeout('Lint Golang', 10) { + sh 'make go-style' + } + + runStageWithTimeout('Build Golang bins', 10) { + sh 'make go-bins' + } + + runStageWithTimeout('Test Golang', 10) { + sh 'make go-unit-tests' + } + + }, "Build + Test Web Content (Angular)": { + runStageWithTimeout('Pull Web Content Builder Image', 10) { + sh 'make pull-web-image' + } + + runStageWithTimeout('Setup Web Content', 10) { + sh 'make web-setup' + } + + runStageWithTimeout('Lint Web Content', 10) { + sh 'make lint-web-content' + } + + runStageWithTimeout('Build Web Content', 10) { + sh 'make web-content' + } + + runStageWithTimeout('Test Web Content', 10) { + sh 'make test-web-content' + } + } + + parallel "pure1-unplugged docker image": { + runStageWithTimeout('Build Docker Image', 20) { + sh 'make pure1-unplugged-image' + sh './scripts/push_pure1_unplugged_docker_image.sh' + } + }, "lorax-build docker image": { + runStageWithTimeout('Build Lorax Docker Image', 20) { + sh 'make lorax-image' + } + } + + runStageWithTimeout('Build Helm Chart', 10) { + sh 'make helm-chart' + } + + runStageWithTimeout('Build Install Bundle', 90) { + sh 'make install-bundle' + } + + runStageWithTimeout('Build Pure1-Unplugged RPM', 90) { + sh 'make rpm' + } + + runStageWithTimeout('Build Installer ISO', 90) { + sh 'make iso' + } + + } finally { + archiveArtifacts allowEmptyArchive: true, artifacts: 'build/bin/**/*', defaultExcludes: false, fingerprint: false + archiveArtifacts allowEmptyArchive: true, artifacts: 'build/gui/**/*', defaultExcludes: false, fingerprint: false + archiveArtifacts allowEmptyArchive: true, artifacts: 'build/chart/*.tgz', defaultExcludes: false, fingerprint: false + archiveArtifacts allowEmptyArchive: true, artifacts: 'build/iso/*.iso', defaultExcludes: false, fingerprint: true + archiveArtifacts allowEmptyArchive: true, artifacts: 'build/bundle/*.tar.gz', defaultExcludes: false, fingerprint: true + archiveArtifacts allowEmptyArchive: true, artifacts: 'build/bundle/*.tar.gz.sha1', defaultExcludes: false, fingerprint: true + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT 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/Makefile b/Makefile new file mode 100644 index 00000000..0de6d082 --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ + +all-rpm: clean go web pure1-unplugged-image lorax-image helm-chart install-bundle rpm + +all: all-rpm iso + +all-minikube: clean go web pure1-unplugged-image-minikube lorax-image helm-chart + +clean: + rm -rf ./build + +go: pull-go-image go-all + +pull-go-image: + ./scripts/pull_gobuilder.sh + +# Match any target that starts with 'go-' and shim them into the docker container where we run +# the target there without the 'go-' prefix. Example: make go-auth-server will run (in docker) +# something like make -f ./Makefile-golang auth-server +go-%: + ./scripts/build/build_golang_in_docker.sh $* + +web: pull-web-image web-setup lint-web-content test-web-content web-content + +pull-web-image: + ./scripts/pull_angularbuilder.sh + +web-setup: + ./scripts/setup_web_content_in_docker.sh + +lint-web-content: + ./scripts/build/lint_web_content_in_docker.sh + +web-content: + ./scripts/build/build_web_content_in_docker.sh + +test-web-content: + ./scripts/build/test_web_content_in_docker.sh + +pure1-unplugged-image: + ./scripts/build/build_pure1_unplugged_image.sh + +pure1-unplugged-image-minikube: + ./scripts/build/build_pure1_unplugged_image.sh minikube + +lorax-image: + ./scripts/build/build_lorax_image.sh + +helm-chart: + ./scripts/build/build_helm_chart_in_docker.sh + +install-bundle: + ./scripts/build/build_install_bundle_in_docker.sh + +rpm: + ./scripts/build/build_pure1_unplugged_rpm_in_docker.sh + +iso: + ./scripts/build/build_installer_iso_in_docker.sh + +.PHONY: all-rpm all-minikube clean go pull-go-image web pull-web-image web-setup pure1-unplugged-image pure1-unplugged-image-minikube lorax-image helm-chart install-bundle rpm install-iso diff --git a/Makefile-golang b/Makefile-golang new file mode 100644 index 00000000..059c0b46 --- /dev/null +++ b/Makefile-golang @@ -0,0 +1,50 @@ +VERSION=$(shell ./scripts/generate_version.sh ./) + +VERSION_HOOK=github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/version.buildVersion + +ALL_PKG=./pkg/... ./cmd/... +BIN_DIR=./build/bin + +LDFLAGS= -X $(VERSION_HOOK)='$(VERSION)' -linkmode external -extldflags '-static' +GOBUILD= CC=/usr/local/musl/bin/musl-gcc go build --ldflags "$(LDFLAGS)" + +all: clean style bins + +clean: + go clean $(ALL_PKG) + rm -rf $(BIN_DIR) + +prep: fmt style + +bins: auth-server api-server metrics-client monitor-server puctl + +puctl: + $(GOBUILD) ./cmd/puctl + mkdir -p $(BIN_DIR) && mv -f puctl $(BIN_DIR)/ + +api-server: + $(GOBUILD) ./cmd/api-server + mkdir -p $(BIN_DIR) && mv -f api-server $(BIN_DIR)/pure1-unplugged-api-server + +auth-server: + $(GOBUILD) ./cmd/auth-server + mkdir -p $(BIN_DIR) && mv -f auth-server $(BIN_DIR)/pure1-unplugged-auth-server + +metrics-client: + $(GOBUILD) ./cmd/metrics-client + mkdir -p $(BIN_DIR) && mv -f metrics-client $(BIN_DIR)/pure1-unplugged-metrics-client + +monitor-server: + $(GOBUILD) ./cmd/monitor-server + mkdir -p $(BIN_DIR) && mv -f monitor-server $(BIN_DIR)/pure1-unplugged-monitor-server + +unit-tests: + /coverage.sh $(ALL_PKG) + +fmt: + go fmt $(ALL_PKG) + +style: + /check-style.sh $(ALL_PKG) + +.PHONY: clean style fmt prep bins puctl api-server auth-server metrics-client monitor-server unit-tests diff --git a/README.md b/README.md new file mode 100644 index 00000000..1ac9df09 --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +# Pure1 Unplugged +Pure Storage's open-source on-premise fleet monitoring solution. + +## Installation +Pure1 Unplugged can be installed from an ISO or an OVA. The latest versions, along with documentation, are pre-created and are available to download for free. Documentation is also available online. + +### Links +http://dl-west.purestorage.com/pure/pure1-unplugged/download + +https://support.purestorage.com/Pure1/Pure1_Unplugged. + +## Development +Pure1 Unplugged can be built and run locally. + +### Prerequisites +1. Forked and cloned source code +2. Minikube and required hypervisor: https://kubernetes.io/docs/tasks/tools/install-minikube/ + +### Building +There are two separate Makefiles for building and testing. The main [Makefile](./Makefile) builds all available targets. The sub-Makefile +[Makefile-golang](./Makefile-golang) has targets for building golang in a docker container. The top level Makefile looks for any target that matches the pattern `go-%` and will launch a container and make inside the container with the targets matching pattern. + +_Example_: `make go-clean go-prep go-auth-server` runs the targets `clean prep auth-server` in a container. + +### Testing +* Golang: `make go-unit-tests` +* Web content: `make test-web-content` + +### Local deployment +1. Start minikube with at least 6GB memory and 40GB disk + * `minikube start --memory 6144 --disk-size 40g` +2. Build with `make all-minikube` + * Note that build output goes into `./build/*`, and this `minikube` build mode will *not* create the installer ISO +3. Deploy with `./scripts/deploy/helm_install.sh $(minikube ip)` + * Note that the deployment name must be `pure1-unplugged` +4. Run `minikube ip` and navigate to it in your browser +5. Log in with example + +_Hint:_ Set `kubectl` to use `pure1-unplugged` namespace by running `kubectl config set-context $(kubectl config current-context) --namespace=pure1-unplugged` for easier use. + +### Updating a deployment + +#### Updating golang +``` +make go-bins +make pure-elk-image-minikube +make lorax-image +make helm-chart +helm upgrade pure-elk build/chart/*.tgz --force +``` + +#### Updating web content +``` +make web-content +make pure-elk-image-minikube +make lorax-image +make helm-chart +helm upgrade pure-elk build/chart/*.tgz --force +``` + +## Contributions + +### Changes +As Pure1 Unplugged is open-source, we welcome all contributions. We will also be providing improvements and new features. + +1. Create a public fork of the repository +2. Send a pull request (we need to create a reviewer group for us) +3. We will test and validate your code +4. Merge the pull request +5. We will update the ISO and OVA to download and comment on the pull request + +### Issues +We will also monitor issues listed on GitHub, as well as create issues ourselves. All changes should reference an issue. + diff --git a/ThirdPartySoftware.md b/ThirdPartySoftware.md new file mode 100644 index 00000000..5282efe9 --- /dev/null +++ b/ThirdPartySoftware.md @@ -0,0 +1,1080 @@ +# Primary Software +| Software | License | License URL | +|------------------------------------------------|------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------| +| Kubernetes (Kubeadm, Kubectl, Kubelet) 1.13.14 | Apache-2.0 | https://github.com/kubernetes/kubernetes/raw/master/LICENSE | +| Helm 2.13.0 | Apache-2.0 | https://github.com/helm/helm/raw/master/LICENSE | +| Docker CE 18.06.1 | Apache-2.0 | https://github.com/docker/docker-ce/raw/master/components/cli/LICENSE | +| Elasticsearch 1.17.0 | Apache-2.0 | https://github.com/elastic/elasticsearch/raw/master/LICENSE.txt | +| Kibana 1.1.2 | Apache-2.0 | https://github.com/elastic/kibana/raw/master/LICENSE.txt | +| NGINX Ingress chart 1.3.1 | Apache-2.0 | https://github.com/kubernetes/ingress-nginx/raw/master/LICENSE | +| Helm charts repo | Apache-2.0 | https://github.com/helm/charts/raw/master/LICENSE | +| Dex 2.12.0 | Apache-2.0 | https://github.com/dexidp/dex/raw/master/LICENSE | +| Angular 6 | MIT | https://github.com/angular/angular/raw/master/LICENSE | +| Dep | | https://github.com/golang/dep/raw/master/LICENSE | +| Swagger image 3.20.7 | Apache-2.0 | https://github.com/swagger-api/swagger-ui/raw/master/LICENSE | +| CentOS 7.6.1810 | | | +| Calico 3.5.2 | Apache-2.0 | https://github.com/projectcalico/calico/raw/master/LICENSE | + +# Web Content Dependencies +| module name | licenses | licenseUrl | +|------------------------------------------------|-------------------------------------|-----------------------------------------------------------------------------------------------------------------------| +| @angular-devkit/architect@0.6.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @angular-devkit/build-angular@0.6.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @angular-devkit/build-optimizer@0.6.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @angular-devkit/core@0.6.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @angular-devkit/schematics@0.6.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @angular/animations@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/cli@6.0.8 | MIT | https://github.com/angular/angular-cli/raw/master/LICENSE | +| @angular/common@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/compiler-cli@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/compiler@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/core@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/forms@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/http@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/language-service@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/platform-browser-dynamic@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/platform-browser@6.0.4 | MIT | https://github.com/angular/angular | +| @angular/router@6.0.4 | MIT | https://github.com/angular/angular | +| @ng-bootstrap/ng-bootstrap@2.2.0 | MIT | https://github.com/ng-bootstrap/ng-bootstrap/raw/master/LICENSE | +| @ngtools/webpack@6.0.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @schematics/angular@0.6.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @schematics/update@0.6.8 | MIT | https://github.com/angular/devkit/raw/master/LICENSE | +| @types/d3-array@1.2.1 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-axis@1.0.10 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-brush@1.0.8 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-chord@1.0.7 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-collection@1.0.7 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-color@1.2.1 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-contour@1.2.1 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-dispatch@1.0.6 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-drag@1.2.1 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-dsv@1.0.33 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-ease@1.0.7 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-fetch@1.1.2 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-force@1.1.1 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-format@1.3.0 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-geo@1.10.3 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-hierarchy@1.1.3 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-interpolate@1.2.0 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-path@1.0.7 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-polygon@1.0.6 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-quadtree@1.0.6 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-random@1.1.1 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-scale-chromatic@1.2.0 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-scale@2.0.1 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-selection@1.3.2 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-shape@1.2.3 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-time-format@2.1.0 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-time@1.0.8 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-timer@1.0.7 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-transition@1.1.2 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3-voronoi@1.1.7 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/d3-zoom@1.7.1 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/d3@5.0.0 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/geojson@7946.0.4 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/jasmine@2.8.8 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/jasminewd2@2.0.3 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/node@6.0.112 | MIT | https://github.com/DefinitelyTyped/DefinitelyTyped/raw/master/LICENSE | +| @types/node@8.9.5 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/q@0.0.32 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @types/selenium-webdriver@2.53.43 | MIT | https://wwwhub.com/DefinitelyTyped/DefinitelyTyped | +| @webassemblyjs/ast@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/floating-point-hex-parser@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs/raw/master/LICENSE | +| @webassemblyjs/helper-buffer@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/helper-code-frame@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/helper-fsm@1.4.3 | ISC | https://github.com/xtuc/webassemblyjs/raw/master/LICENSE | +| @webassemblyjs/helper-wasm-bytecode@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/helper-wasm-section@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/leb128@1.4.3 | Apache-2.0 | https://github.com/xtuc/webassemblyjs/raw/master/packages/leb128/LICENSE.txt | +| @webassemblyjs/validation@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/wasm-edit@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/wasm-gen@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/wasm-opt@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/wasm-parser@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/wast-parser@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| @webassemblyjs/wast-printer@1.4.3 | MIT | https://github.com/xtuc/webassemblyjs | +| abbrev@1.0.9 | ISC | http://github.com/isaacs/abbrev-js/raw/master/LICENSE | +| abbrev@1.1.1 | ISC | https://github.com/isaacs/abbrev-js/raw/master/LICENSE | +| accepts@1.3.3 | MIT | https://github.com/jshttp/accepts/raw/master/LICENSE | +| accepts@1.3.5 | MIT | https://github.com/jshttp/accepts/raw/master/LICENSE | +| acorn-dynamic-import@3.0.0 | MIT | https://github.com/kesne/acorn-dynamic-import/raw/master/LICENSE | +| acorn@5.6.2 | MIT | https://github.com/acornjs/acorn/raw/master/LICENSE | +| adm-zip@0.4.11 | MIT | https://github.com/cthackers/adm-zip | +| adm-zip@0.4.4 | MIT | https://raw.github.com/cthackers/adm-zip/master/MIT-LICENSE.txt | +| after@0.8.2 | MIT | https://github.com/Raynos/after/raw/master/LICENCE | +| agent-base@4.2.0 | MIT | https://github.com/TooTallNate/node-agent-base | +| ajv-keywords@3.2.0 | MIT | https://github.com/epoberezkin/ajv-keywords/raw/master/LICENSE | +| ajv@5.5.2 | MIT | https://github.com/epoberezkin/ajv/raw/master/LICENSE | +| ajv@6.4.0 | MIT | https://github.com/epoberezkin/ajv/raw/master/LICENSE | +| align-text@0.1.4 | MIT | https://github.com/jonschlinkert/align-text/raw/master/LICENSE | +| amdefine@1.0.1 | BSD-3-Clause OR MIT | https://github.com/jrburke/amdefine/raw/master/LICENSE | +| ansi-html@0.0.7 | Apache-2.0 | https://github.com/Tjatse/ansi-html/raw/master/LICENSE | +| ansi-regex@2.1.1 | MIT | https://github.com/chalk/ansi-regex/raw/master/license | +| ansi-regex@3.0.0 | MIT | https://github.com/chalk/ansi-regex/raw/master/license | +| ansi-styles@2.2.1 | MIT | https://github.com/chalk/ansi-styles/raw/master/license | +| ansi-styles@3.2.1 | MIT | https://github.com/chalk/ansi-styles/raw/master/license | +| anymatch@1.3.2 | ISC | https://github.com/es128/anymatch/raw/master/LICENSE | +| anymatch@2.0.0 | ISC | https://github.com/micromatch/anymatch/raw/master/LICENSE | +| app-root-path@2.0.1 | MIT | https://github.com/inxilpro/node-app-root-path/raw/master/LICENSE | +| append-transform@1.0.0 | MIT | https://github.com/istanbuljs/append-transform/raw/master/license | +| aproba@1.2.0 | ISC | https://github.com/iarna/aproba/raw/master/LICENSE | +| are-we-there-yet@1.1.4 | ISC | https://github.com/iarna/are-we-there-yet/raw/master/LICENSE | +| are-we-there-yet@1.1.5 | ISC | https://github.com/iarna/are-we-there-yet/raw/master/LICENSE | +| argparse@1.0.10 | MIT | https://github.com/nodeca/argparse/raw/master/LICENSE | +| arr-diff@2.0.0 | MIT | https://github.com/jonschlinkert/arr-diff/raw/master/LICENSE | +| arr-diff@4.0.0 | MIT | https://github.com/jonschlinkert/arr-diff/raw/master/LICENSE | +| arr-flatten@1.1.0 | MIT | https://github.com/jonschlinkert/arr-flatten/raw/master/LICENSE | +| arr-union@3.1.0 | MIT | https://github.com/jonschlinkert/arr-union/raw/master/LICENSE | +| array-find-index@1.0.2 | MIT | https://github.com/sindresorhus/array-find-index/raw/master/license | +| array-flatten@1.1.1 | MIT | https://github.com/blakeembrey/array-flatten/raw/master/LICENSE | +| array-flatten@2.1.1 | MIT | https://github.com/blakeembrey/array-flatten/raw/master/LICENSE | +| array-includes@3.0.3 | MIT | https://github.com/ljharb/array-includes/raw/master/LICENSE | +| array-slice@0.2.3 | MIT | https://github.com/jonschlinkert/array-slice/blob/master/LICENSE | +| array-union@1.0.2 | MIT | https://github.com/sindresorhus/array-union/raw/master/license | +| array-uniq@1.0.3 | MIT | https://github.com/sindresorhus/array-uniq/raw/master/license | +| array-unique@0.2.1 | MIT | https://github.com/jonschlinkert/array-unique/blob/master/LICENSE | +| array-unique@0.3.2 | MIT | https://github.com/jonschlinkert/array-unique/raw/master/LICENSE | +| arraybuffer.slice@0.0.6 | MIT* | https://github.com/rase-/arraybuffer.slice/raw/master/README.md | +| arrify@1.0.1 | MIT | https://github.com/sindresorhus/arrify/raw/master/license | +| asap@2.0.6 | MIT | https://github.com/kriskowal/asap/raw/master/LICENSE.md | +| asn1.js@4.10.1 | MIT | https://github.com/indutny/asn1.js | +| asn1@0.2.3 | MIT | https://github.com/mcavage/node-asn1/raw/master/LICENSE | +| assert-plus@0.2.0 | MIT | https://github.com/mcavage/node-assert-plus | +| assert-plus@1.0.0 | MIT | https://github.com/mcavage/node-assert-plus | +| assert@1.4.1 | MIT | https://github.com/defunctzombie/commonjs-assert/raw/master/LICENSE | +| assign-symbols@1.0.0 | MIT | https://github.com/jonschlinkert/assign-symbols/raw/master/LICENSE | +| async-each@1.0.1 | MIT | https://github.com/paulmillr/async-each | +| async-foreach@0.1.3 | MIT* | https://github.com/cowboy/javascript-sync-async-foreach/raw/master/LICENSE-MIT | +| async@1.5.2 | MIT | https://github.com/caolan/async/raw/master/LICENSE | +| async@2.6.1 | MIT | https://github.com/caolan/async/raw/master/LICENSE | +| asynckit@0.4.0 | MIT | https://github.com/alexindigo/asynckit/raw/master/LICENSE | +| atob@2.1.1 | (MIT OR Apache-2.0) | https://git.coolaj86.com/coolaj86/atob.js | +| autoprefixer@8.6.0 | MIT | https://github.com/postcss/autoprefixer/raw/master/LICENSE | +| aws-sign2@0.6.0 | Apache-2.0 | https://github.com/mikeal/aws-sign/raw/master/LICENSE | +| aws-sign2@0.7.0 | Apache-2.0 | https://github.com/mikeal/aws-sign/raw/master/LICENSE | +| aws4@1.7.0 | MIT | https://github.com/mhart/aws4/raw/master/LICENSE | +| babel-code-frame@6.26.0 | MIT | https://github.com/babel/babel/tree/master/packages/babel-code-frame | +| babel-generator@6.26.1 | MIT | https://github.com/babel/babel/tree/master/packages/babel-generator | +| babel-messages@6.23.0 | MIT | https://github.com/babel/babel/tree/master/packages/babel-messages | +| babel-runtime@6.26.0 | MIT | https://github.com/babel/babel/tree/master/packages/babel-runtime | +| babel-template@6.26.0 | MIT | https://github.com/babel/babel/tree/master/packages/babel-template | +| babel-traverse@6.26.0 | MIT | https://github.com/babel/babel/tree/master/packages/babel-traverse | +| babel-types@6.26.0 | MIT | https://github.com/babel/babel/tree/master/packages/babel-types | +| babylon@6.18.0 | MIT | https://github.com/babel/babylon/raw/master/LICENSE | +| backo2@1.0.2 | MIT | https://github.com/mokesmokes/backo | +| balanced-match@1.0.0 | MIT | https://github.com/juliangruber/balanced-match/raw/master/LICENSE.md | +| base@0.11.2 | MIT | https://github.com/node-base/base/raw/master/LICENSE | +| base64-arraybuffer@0.1.5 | MIT | https://github.com/niklasvh/base64-arraybuffer/blob/master/LICENSE-MIT | +| base64-js@1.3.0 | MIT | https://github.com/beatgammit/base64-js/raw/master/LICENSE | +| base64id@1.0.0 | MIT | https://github.com/faeldt/base64id/raw/master/LICENSE | +| batch@0.6.1 | MIT | https://github.com/visionmedia/batch/raw/master/LICENSE | +| bcrypt-pbkdf@1.0.1 | BSD-3-Clause | https://github.com/joyent/node-bcrypt-pbkdf/raw/master/LICENSE | +| better-assert@1.0.2 | MIT* | https://github.com/visionmedia/better-assert/raw/master/Readme.md | +| big.js@3.2.0 | MIT | https://github.com/MikeMcl/big.js/raw/master/LICENCE | +| binary-extensions@1.11.0 | MIT | https://github.com/sindresorhus/binary-extensions/raw/master/license | +| blob@0.0.4 | MIT* | https://github.com/rase-/blob/raw/master/README.md | +| block-stream@0.0.9 | ISC | https://github.com/isaacs/block-stream/raw/master/LICENCE | +| blocking-proxy@1.0.1 | MIT | https://github.com/angular/jasminewd/raw/master/LICENSE | +| bluebird@3.5.1 | MIT | https://github.com/petkaantonov/bluebird/raw/master/LICENSE | +| bn.js@4.11.8 | MIT | https://github.com/indutny/bn.js | +| body-parser@1.18.2 | MIT | https://github.com/expressjs/body-parser/raw/master/LICENSE | +| bonjour@3.5.0 | MIT | https://github.com/watson/bonjour/raw/master/LICENSE | +| boolbase@1.0.0 | ISC | https://github.com/fb55/boolbase | +| boom@2.10.1 | BSD-3-Clause | https://github.com/hapijs/boom/raw/master/LICENSE | +| bootstrap@4.1.1 | MIT | https://github.com/twbs/bootstrap/raw/master/LICENSE | +| brace-expansion@1.1.11 | MIT | https://github.com/juliangruber/brace-expansion/raw/master/LICENSE | +| braces@0.1.5 | MIT | https://github.com/jonschlinkert/braces/blob/master/LICENSE-MIT | +| braces@1.8.5 | MIT | https://github.com/jonschlinkert/braces/raw/master/LICENSE | +| braces@2.3.2 | MIT | https://github.com/micromatch/braces/raw/master/LICENSE | +| brorand@1.1.0 | MIT | https://github.com/indutny/brorand | +| browserify-aes@1.2.0 | MIT | https://github.com/crypto-browserify/browserify-aes/raw/master/LICENSE | +| browserify-cipher@1.0.1 | MIT | https://github.com/crypto-browserify/browserify-cipher/raw/master/LICENSE | +| browserify-des@1.0.1 | MIT | https://github.com/crypto-browserify/browserify-des/raw/master/license | +| browserify-rsa@4.0.1 | MIT | https://github.com/crypto-browserify/browserify-rsa/raw/master/LICENSE | +| browserify-sign@4.0.4 | ISC | https://github.com/crypto-browserify/browserify-sign/raw/master/LICENSE | +| browserify-zlib@0.2.0 | MIT | https://github.com/devongovett/browserify-zlib/raw/master/LICENSE | +| browserslist@3.2.8 | MIT | https://github.com/browserslist/browserslist/raw/master/LICENSE | +| buffer-from@1.1.0 | MIT | https://github.com/LinusU/buffer-from | +| buffer-indexof@1.1.1 | MIT | https://github.com/soldair/node-buffer-indexof/raw/master/LICENSE | +| buffer-xor@1.0.3 | MIT | https://github.com/crypto-browserify/buffer-xor/raw/master/LICENSE | +| buffer@4.9.1 | MIT | https://github.com/feross/buffer/raw/master/LICENSE | +| builtin-modules@1.1.1 | MIT | https://github.com/sindresorhus/builtin-modules/raw/master/license | +| builtin-status-codes@3.0.0 | MIT | https://github.com/bendrucker/builtin-status-codes/raw/master/license | +| builtins@1.0.3 | MIT | https://github.com/juliangruber/builtins/raw/master/License | +| bytes@3.0.0 | MIT | https://github.com/visionmedia/bytes.js/raw/master/LICENSE | +| cacache@10.0.4 | ISC | https://github.com/zkat/cacache/raw/master/LICENSE.md | +| cache-base@1.0.1 | MIT | https://github.com/jonschlinkert/cache-base/raw/master/LICENSE | +| cache-loader@1.2.2 | MIT | https://github.com/webpack-contrib/cache-loader/raw/master/LICENSE | +| callsite@1.0.0 | MIT* | https://github.com/tj/callsite/raw/master/LICENSE | +| camel-case@3.0.0 | MIT | https://github.com/blakeembrey/camel-case/raw/master/LICENSE | +| camelcase-keys@2.1.0 | MIT | https://github.com/sindresorhus/camelcase-keys/raw/master/license | +| camelcase@1.2.1 | MIT | https://github.com/sindresorhus/camelcase/raw/master/license | +| camelcase@2.1.1 | MIT | https://github.com/sindresorhus/camelcase/raw/master/license | +| camelcase@3.0.0 | MIT | https://github.com/sindresorhus/camelcase/raw/master/license | +| camelcase@4.1.0 | MIT | https://github.com/sindresorhus/camelcase/raw/master/license | +| caniuse-lite@1.0.30000849 | CC-BY-4.0 | https://github.com/ben-eb/caniuse-lite/raw/master/LICENSE | +| caseless@0.11.0 | Apache-2.0 | https://github.com/mikeal/caseless/raw/master/LICENSE | +| caseless@0.12.0 | Apache-2.0 | https://github.com/mikeal/caseless/raw/master/LICENSE | +| center-align@0.1.3 | MIT | https://github.com/jonschlinkert/center-align/raw/master/LICENSE | +| chalk@1.1.3 | MIT | https://github.com/chalk/chalk/raw/master/license | +| chalk@2.2.2 | MIT | https://github.com/chalk/chalk/raw/master/license | +| chalk@2.4.1 | MIT | https://github.com/chalk/chalk/raw/master/license | +| chokidar@1.7.0 | MIT | https://github.com/paulmillr/chokidar | +| chokidar@2.0.3 | MIT | https://github.com/paulmillr/chokidar | +| chownr@1.0.1 | ISC | https://github.com/isaacs/chownr/raw/master/LICENSE | +| chrome-trace-event@0.1.3 | MIT | github.com:samccone/chrome-trace-event/raw/master/LICENSE.txt | +| cipher-base@1.0.4 | MIT | https://github.com/crypto-browserify/cipher-base/raw/master/LICENSE | +| circular-dependency-plugin@5.0.2 | ISC | https://github.com/aackerman/circular-dependency-plugin/raw/master/LICENSE | +| class-utils@0.3.6 | MIT | https://github.com/jonschlinkert/class-utils/raw/master/LICENSE | +| clean-css@4.1.11 | MIT | https://github.com/jakubpawlowicz/clean-css/raw/master/LICENSE | +| cliui@2.1.0 | ISC | http://github.com/bcoe/cliui/raw/master/LICENSE.txt | +| cliui@3.2.0 | ISC | http://github.com/yargs/cliui/raw/master/LICENSE.txt | +| cliui@4.1.0 | ISC | http://github.com/yargs/cliui/raw/master/LICENSE.txt | +| clone-deep@2.0.2 | MIT | https://github.com/jonschlinkert/clone-deep/raw/master/LICENSE | +| clone@2.1.1 | MIT | https://github.com/pvorb/node-clone/raw/master/LICENSE | +| co@4.6.0 | MIT | https://github.com/tj/co/raw/master/LICENSE | +| code-point-at@1.1.0 | MIT | https://github.com/sindresorhus/code-point-at/raw/master/license | +| codelyzer@4.2.1 | MIT | https://github.com/mgechev/codelyzer | +| collection-visit@1.0.0 | MIT | https://github.com/jonschlinkert/collection-visit/raw/master/LICENSE | +| color-convert@1.9.1 | MIT | https://github.com/Qix-/color-convert/raw/master/LICENSE | +| color-name@1.1.3 | MIT | https://github.com/dfcreative/color-name/raw/master/LICENSE | +| colors@1.1.2 | MIT | http://github.com/Marak/colors.js/raw/master/LICENSE | +| combine-lists@1.0.1 | MIT | https://github.com/sjelin/combine-lists/raw/master/LICENSE | +| combined-stream@1.0.6 | MIT | https://github.com/felixge/node-combined-stream/raw/master/License | +| commander@2.13.0 | MIT | https://github.com/tj/commander.js/raw/master/LICENSE | +| commander@2.15.1 | MIT | https://github.com/tj/commander.js/raw/master/LICENSE | +| commondir@1.0.1 | MIT | http://github.com/substack/node-commondir/raw/master/LICENSE | +| compare-versions@3.2.1 | MIT | https://github.com/omichelsen/compare-versions/raw/master/LICENSE | +| component-bind@1.0.0 | MIT* | https://github.com/component/bind/raw/master/Readme.md | +| component-emitter@1.1.2 | MIT* | https://github.com/component/emitter/raw/master/Readme.md | +| component-emitter@1.2.1 | MIT | https://github.com/component/emitter/raw/master/LICENSE | +| component-inherit@0.0.3 | MIT* | https://github.com/component/inherit/raw/master/Readme.md | +| compressible@2.0.14 | MIT | https://github.com/jshttp/compressible/raw/master/LICENSE | +| compression@1.7.2 | MIT | https://github.com/expressjs/compression/raw/master/LICENSE | +| concat-map@0.0.1 | MIT | https://github.com/substack/node-concat-map/raw/master/LICENSE | +| concat-stream@1.6.2 | MIT | http://github.com/maxogden/concat-stream/raw/master/LICENSE | +| connect-history-api-fallback@1.5.0 | MIT | http://github.com/bripkens/connect-history-api-fallback/raw/master/LICENSE | +| connect@3.6.6 | MIT | https://github.com/senchalabs/connect/raw/master/LICENSE | +| console-browserify@1.1.0 | MIT | http://github.com/Raynos/console-browserify/raw/master/LICENSE | +| console-control-strings@1.1.0 | ISC | https://github.com/iarna/console-control-strings/raw/master/LICENSE | +| constants-browserify@1.0.0 | MIT | https://github.com/juliangruber/constants-browserify | +| content-disposition@0.5.2 | MIT | https://github.com/jshttp/content-disposition/raw/master/LICENSE | +| content-type@1.0.4 | MIT | https://github.com/jshttp/content-type/raw/master/LICENSE | +| convert-source-map@1.5.1 | MIT | https://github.com/thlorenz/convert-source-map/raw/master/LICENSE | +| cookie-signature@1.0.6 | MIT | https://github.com/visionmedia/node-cookie-signature | +| cookie@0.3.1 | MIT | https://github.com/jshttp/cookie/raw/master/LICENSE | +| copy-concurrently@1.0.5 | ISC | https://github.com/npm/copy-concurrently/raw/master/LICENSE | +| copy-descriptor@0.1.1 | MIT | https://github.com/jonschlinkert/copy-descriptor/raw/master/LICENSE | +| copy-webpack-plugin@4.5.1 | MIT | https://github.com/webpack-contrib/copy-webpack-plugin/raw/master/LICENSE | +| core-js@2.3.0 | MIT | https://github.com/zloirock/core-js/raw/master/LICENSE | +| core-js@2.5.7 | MIT | https://github.com/zloirock/core-js/raw/master/LICENSE | +| core-util-is@1.0.2 | MIT | https://github.com/isaacs/core-util-is/raw/master/LICENSE | +| cosmiconfig@2.2.2 | MIT | https://github.com/davidtheclark/cosmiconfig/raw/master/LICENSE | +| create-ecdh@4.0.3 | MIT | https://github.com/crypto-browserify/createECDH/raw/master/LICENSE | +| create-hash@1.2.0 | MIT | https://github.com/crypto-browserify/createHash/raw/master/LICENSE | +| create-hmac@1.1.7 | MIT | https://github.com/crypto-browserify/createHmac/raw/master/LICENSE | +| cross-spawn@3.0.1 | MIT | https://github.com/IndigoUnited/node-cross-spawn/raw/master/LICENSE | +| cross-spawn@5.1.0 | MIT | https://github.com/IndigoUnited/node-cross-spawn/raw/master/LICENSE | +| cryptiles@2.0.5 | BSD-3-Clause | https://github.com/hapijs/cryptiles/raw/master/LICENSE | +| crypto-browserify@3.12.0 | MIT | https://github.com/crypto-browserify/crypto-browserify/raw/master/LICENSE | +| css-parse@1.7.0 | MIT | https://github.com/visionmedia/css-parse | +| css-select@1.2.0 | BSD-like | https://github.com/fb55/css-select/raw/master/LICENSE | +| css-selector-tokenizer@0.7.0 | MIT | https://github.com/css-modules/css-selector-tokenizer | +| css-what@2.1.0 | BSD-like | https://github.com/fb55/css-what/raw/master/LICENSE | +| cssauron@1.4.0 | MIT | https://github.com/chrisdickinson/cssauron | +| cssesc@0.1.0 | MIT | http://mths.be/mit | +| cuint@0.2.2 | MIT | https://github.com/pierrec/js-cuint | +| currently-unhandled@0.4.1 | MIT | https://github.com/jamestalmage/currently-unhandled/raw/master/license | +| custom-event@1.0.1 | MIT | https://github.com/webmodules/custom-event/raw/master/LICENSE | +| cyclist@0.2.2 | MIT* | https://github.com/mafintosh/cyclist/raw/master/README.md | +| d@1.0.0 | MIT | https://github.com/medikoo/d/raw/master/LICENSE | +| d3-array@1.2.1 | BSD-3-Clause | https://github.com/d3/d3-array/raw/master/LICENSE | +| d3-axis@1.0.8 | BSD-3-Clause | https://github.com/d3/d3-axis/raw/master/LICENSE | +| d3-brush@1.0.4 | BSD-3-Clause | https://github.com/d3/d3-brush/raw/master/LICENSE | +| d3-chord@1.0.4 | BSD-3-Clause | https://github.com/d3/d3-chord/raw/master/LICENSE | +| d3-collection@1.0.4 | BSD-3-Clause | https://github.com/d3/d3-collection/raw/master/LICENSE | +| d3-color@1.2.0 | BSD-3-Clause | https://github.com/d3/d3-color/raw/master/LICENSE | +| d3-contour@1.3.0 | BSD-3-Clause | https://github.com/d3/d3-contour/raw/master/LICENSE | +| d3-dispatch@1.0.3 | BSD-3-Clause | https://github.com/d3/d3-dispatch/raw/master/LICENSE | +| d3-drag@1.2.1 | BSD-3-Clause | https://github.com/d3/d3-drag/raw/master/LICENSE | +| d3-dsv@1.0.8 | BSD-3-Clause | https://github.com/d3/d3-dsv/raw/master/LICENSE | +| d3-ease@1.0.3 | BSD-3-Clause | https://github.com/d3/d3-ease/raw/master/LICENSE | +| d3-fetch@1.1.0 | BSD-3-Clause | https://github.com/d3/d3-fetch/raw/master/LICENSE | +| d3-force@1.1.0 | BSD-3-Clause | https://github.com/d3/d3-force/raw/master/LICENSE | +| d3-format@1.3.0 | BSD-3-Clause | https://github.com/d3/d3-format/raw/master/LICENSE | +| d3-geo@1.10.0 | BSD-3-Clause | https://github.com/d3/d3-geo/raw/master/LICENSE | +| d3-hierarchy@1.1.6 | BSD-3-Clause | https://github.com/d3/d3-hierarchy/raw/master/LICENSE | +| d3-interpolate@1.2.0 | BSD-3-Clause | https://github.com/d3/d3-interpolate/raw/master/LICENSE | +| d3-path@1.0.5 | BSD-3-Clause | https://github.com/d3/d3-path/raw/master/LICENSE | +| d3-polygon@1.0.3 | BSD-3-Clause | https://github.com/d3/d3-polygon/raw/master/LICENSE | +| d3-quadtree@1.0.3 | BSD-3-Clause | https://github.com/d3/d3-quadtree/raw/master/LICENSE | +| d3-random@1.1.0 | BSD-3-Clause | https://github.com/d3/d3-random/raw/master/LICENSE | +| d3-scale-chromatic@1.3.0 | BSD-3-Clause | https://github.com/d3/d3-scale-chromatic/raw/master/LICENSE | +| d3-scale@2.1.0 | BSD-3-Clause | https://github.com/d3/d3-scale/raw/master/LICENSE | +| d3-selection@1.3.0 | BSD-3-Clause | https://github.com/d3/d3-selection/raw/master/LICENSE | +| d3-shape@1.2.0 | BSD-3-Clause | https://github.com/d3/d3-shape/raw/master/LICENSE | +| d3-time-format@2.1.1 | BSD-3-Clause | https://github.com/d3/d3-time-format/raw/master/LICENSE | +| d3-time@1.0.8 | BSD-3-Clause | https://github.com/d3/d3-time/raw/master/LICENSE | +| d3-timer@1.0.7 | BSD-3-Clause | https://github.com/d3/d3-timer/raw/master/LICENSE | +| d3-transition@1.1.1 | BSD-3-Clause | https://github.com/d3/d3-transition/raw/master/LICENSE | +| d3-voronoi@1.1.2 | BSD-3-Clause | https://github.com/d3/d3-voronoi/raw/master/LICENSE | +| d3-zoom@1.7.1 | BSD-3-Clause | https://github.com/d3/d3-zoom/raw/master/LICENSE | +| d3@5.5.0 | BSD-3-Clause | https://github.com/d3/d3/raw/master/LICENSE | +| dashdash@1.14.1 | MIT | https://github.com/trentm/node-dashdash/raw/master/LICENSE.txt | +| date-now@0.1.4 | MIT | http://github.com/Colingo/date-now/raw/master/LICENSE | +| debug@2.2.0 | MIT | https://github.com/visionmedia/debug | +| debug@2.3.3 | MIT | https://github.com/visionmedia/debug/raw/master/LICENSE | +| debug@2.6.9 | MIT | https://github.com/visionmedia/debug/raw/master/LICENSE | +| debug@3.1.0 | MIT | https://github.com/visionmedia/debug/raw/master/LICENSE | +| decamelize@1.2.0 | MIT | https://github.com/sindresorhus/decamelize/raw/master/license | +| decode-uri-component@0.2.0 | MIT | https://github.com/SamVerschueren/decode-uri-component/raw/master/license | +| deep-equal@1.0.1 | MIT | http://github.com/substack/node-deep-equal/raw/master/LICENSE | +| deep-extend@0.5.1 | MIT | https://github.com/unclechu/node-deep-extend/raw/master/LICENSE | +| deep-is@0.1.3 | MIT | https://github.com/thlorenz/deep-is/blob/master/LICENSE | +| default-require-extensions@2.0.0 | MIT | https://github.com/avajs/default-require-extensions/raw/master/license | +| define-properties@1.1.2 | MIT | https://github.com/ljharb/define-properties/raw/master/LICENSE | +| define-property@0.2.5 | MIT | https://github.com/jonschlinkert/define-property/raw/master/LICENSE | +| define-property@1.0.0 | MIT | https://github.com/jonschlinkert/define-property/raw/master/LICENSE | +| define-property@2.0.2 | MIT | https://github.com/jonschlinkert/define-property/raw/master/LICENSE | +| del@2.2.2 | MIT | https://github.com/sindresorhus/del/raw/master/license | +| del@3.0.0 | MIT | https://github.com/sindresorhus/del/raw/master/license | +| delayed-stream@1.0.0 | MIT | https://github.com/felixge/node-delayed-stream/raw/master/License | +| delegates@1.0.0 | MIT | https://github.com/visionmedia/node-delegates/raw/master/License | +| depd@1.1.1 | MIT | https://github.com/dougwilson/nodejs-depd/raw/master/LICENSE | +| depd@1.1.2 | MIT | https://github.com/dougwilson/nodejs-depd/raw/master/LICENSE | +| des.js@1.0.0 | MIT | https://github.com/indutny/des.js | +| destroy@1.0.4 | MIT | https://github.com/stream-utils/destroy/raw/master/LICENSE | +| detect-indent@4.0.0 | MIT | https://github.com/sindresorhus/detect-indent/raw/master/license | +| detect-libc@1.0.3 | Apache-2.0 | https://github.com/lovell/detect-libc/raw/master/LICENSE | +| detect-node@2.0.3 | ISC | https://github.com/iliakan/detect-node | +| di@0.0.1 | MIT | https://github.com/vojtajina/node-di/raw/master/LICENSE | +| diff@3.5.0 | BSD-3-Clause | https://github.com/kpdecker/jsdiff/raw/master/LICENSE | +| diffie-hellman@5.0.3 | MIT | https://github.com/crypto-browserify/diffie-hellman/raw/master/LICENSE | +| dir-glob@2.0.0 | MIT | https://github.com/kevva/dir-glob/raw/master/license | +| dns-equal@1.0.0 | MIT | https://github.com/watson/dns-equal/raw/master/LICENSE | +| dns-packet@1.3.1 | MIT | https://github.com/mafintosh/dns-packet/raw/master/LICENSE | +| dns-txt@2.0.2 | MIT | https://github.com/watson/dns-txt/raw/master/LICENSE | +| dom-converter@0.1.4 | MIT | https://github.com/AriaMinaei/dom-converter/raw/master/LICENSE | +| dom-serialize@2.2.1 | MIT | https://github.com/webmodules/dom-serialize | +| dom-serializer@0.1.0 | MIT | https://github.com/cheeriojs/dom-renderer/raw/master/LICENSE | +| domain-browser@1.2.0 | MIT | https://github.com/bevry/domain-browser/raw/master/LICENSE.md | +| domelementtype@1.1.3 | UNKNOWN | https://github.com/FB55/domelementtype/raw/master/LICENSE | +| domelementtype@1.3.0 | UNKNOWN | https://github.com/FB55/domelementtype/raw/master/LICENSE | +| domhandler@2.1.0 | UNKNOWN | https://github.com/fb55/domhandler/raw/master/LICENSE | +| domutils@1.1.6 | UNKNOWN | https://github.com/FB55/domutils/raw/master/LICENSE | +| domutils@1.5.1 | UNKNOWN | https://github.com/FB55/domutils/raw/master/LICENSE | +| duplexify@3.6.0 | MIT | https://github.com/mafintosh/duplexify/raw/master/LICENSE | +| ecc-jsbn@0.1.1 | MIT | https://github.com/quartzjer/ecc-jsbn/raw/master/LICENSE | +| ee-first@1.1.1 | MIT | https://github.com/jonathanong/ee-first/raw/master/LICENSE | +| ejs@2.6.1 | Apache-2.0 | https://github.com/mde/ejs/raw/master/LICENSE | +| electron-to-chromium@1.3.48 | ISC | https://github.com/kilian/electron-to-chromium/ | +| elliptic@6.4.0 | MIT | https://github.com/indutny/elliptic | +| emojis-list@2.1.0 | MIT | https://github.com/kikobeats/emojis-list/raw/master/LICENSE.md | +| encodeurl@1.0.2 | MIT | https://github.com/pillarjs/encodeurl/raw/master/LICENSE | +| end-of-stream@1.4.1 | MIT | https://github.com/mafintosh/end-of-stream/raw/master/LICENSE | +| engine.io-client@1.8.3 | MIT | https://github.com/socketio/engine.io-client/raw/master/LICENSE | +| engine.io-parser@1.3.2 | MIT | https://github.com/socketio/engine.io-parser/raw/master/LICENSE | +| engine.io@1.8.3 | MIT | https://github.com/socketio/engine.io/raw/master/LICENSE | +| enhanced-resolve@4.0.0 | MIT | http://www.opensource.org/licenses/mit-license.php | +| ent@2.2.0 | MIT | https://github.com/substack/node-ent/raw/master/LICENSE | +| entities@1.1.1 | BSD-like | https://github.com/fb55/node-entities/raw/master/LICENSE | +| errno@0.1.7 | MIT | https://github.com/rvagg/node-errno | +| error-ex@1.3.1 | MIT | https://github.com/qix-/node-error-ex/raw/master/LICENSE | +| es-abstract@1.12.0 | MIT | https://github.com/ljharb/es-abstract/raw/master/LICENSE | +| es-to-primitive@1.1.1 | MIT | https://github.com/ljharb/es-to-primitive/raw/master/LICENSE | +| es5-ext@0.10.45 | ISC | https://github.com/medikoo/es5-ext/raw/master/LICENSE | +| es6-iterator@2.0.3 | MIT | https://github.com/medikoo/es6-iterator/raw/master/LICENSE | +| es6-promise@3.0.2 | MIT | https://github.com/jakearchibald/ES6-Promises/raw/master/LICENSE | +| es6-promise@4.2.4 | MIT | https://github.com/stefanpenner/es6-promise/raw/master/LICENSE | +| es6-promisify@5.0.0 | MIT | https://github.com/digitaldesignlabs/es6-promisify | +| es6-symbol@3.1.1 | MIT | https://github.com/medikoo/es6-symbol/raw/master/LICENSE | +| escape-html@1.0.3 | MIT | https://github.com/component/escape-html/raw/master/LICENSE | +| escape-string-regexp@1.0.5 | MIT | https://github.com/sindresorhus/escape-string-regexp/raw/master/license | +| escodegen@1.8.1 | BSD-2-Clause | http://github.com/estools/escodegen/raw/master/LICENSE.BSD | +| eslint-scope@3.7.1 | BSD-2-Clause | https://github.com/eslint/eslint-scope/raw/master/LICENSE | +| esprima@2.7.3 | BSD-2-Clause | https://github.com/jquery/esprima/raw/master/LICENSE.BSD | +| esprima@4.0.0 | BSD-2-Clause | https://github.com/jquery/esprima/raw/master/LICENSE.BSD | +| esrecurse@4.2.1 | BSD-2-Clause | https://github.com/estools/esrecurse | +| estraverse@1.9.3 | BSD | http://github.com/estools/estraverse/raw/master/LICENSE.BSD | +| estraverse@4.2.0 | BSD-2-Clause | http://github.com/estools/estraverse/raw/master/LICENSE.BSD | +| esutils@2.0.2 | BSD | http://github.com/estools/esutils/raw/master/LICENSE.BSD | +| etag@1.8.1 | MIT | https://github.com/jshttp/etag/raw/master/LICENSE | +| eventemitter3@3.1.0 | MIT | https://github.com/primus/eventemitter3/raw/master/LICENSE | +| events@1.1.1 | MIT | https://github.com/Gozala/events/raw/master/LICENSE | +| eventsource@0.1.6 | MIT | http://github.com/aslakhellesoy/eventsource-node/raw/master/LICENSE | +| evp_bytestokey@1.0.3 | MIT | https://github.com/crypto-browserify/EVP_BytesToKey/raw/master/LICENSE | +| execa@0.7.0 | MIT | https://github.com/sindresorhus/execa/raw/master/license | +| exit@0.1.2 | MIT | https://github.com/cowboy/node-exit/blob/master/LICENSE-MIT | +| expand-braces@0.1.2 | MIT | https://github.com/jonschlinkert/expand-braces/raw/master/LICENSE | +| expand-brackets@0.1.5 | MIT | https://github.com/jonschlinkert/expand-brackets/raw/master/LICENSE | +| expand-brackets@2.1.4 | MIT | https://github.com/jonschlinkert/expand-brackets/raw/master/LICENSE | +| expand-range@0.1.1 | MIT | https://github.com/jonschlinkert/expand-range/blob/master/LICENSE-MIT | +| expand-range@1.8.2 | MIT | https://github.com/jonschlinkert/expand-range/raw/master/LICENSE | +| express@4.16.3 | MIT | https://github.com/expressjs/express/raw/master/LICENSE | +| extend-shallow@2.0.1 | MIT | https://github.com/jonschlinkert/extend-shallow/raw/master/LICENSE | +| extend-shallow@3.0.2 | MIT | https://github.com/jonschlinkert/extend-shallow/raw/master/LICENSE | +| extend@3.0.1 | MIT | https://github.com/justmoon/node-extend/raw/master/LICENSE | +| extglob@0.3.2 | MIT | https://github.com/jonschlinkert/extglob/raw/master/LICENSE | +| extglob@2.0.4 | MIT | https://github.com/micromatch/extglob/raw/master/LICENSE | +| extsprintf@1.3.0 | MIT | https://github.com/davepacheco/node-extsprintf/raw/master/LICENSE | +| fast-deep-equal@1.1.0 | MIT | https://github.com/epoberezkin/fast-deep-equal/raw/master/LICENSE | +| fast-json-stable-stringify@2.0.0 | MIT | https://github.com/epoberezkin/fast-json-stable-stringify/raw/master/LICENSE | +| fast-levenshtein@2.0.6 | MIT | https://github.com/hiddentao/fast-levenshtein/raw/master/LICENSE.md | +| fastparse@1.1.1 | MIT | https://github.com/webpack/fastparse | +| faye-websocket@0.10.0 | MIT | https://github.com/faye/faye-websocket-node | +| faye-websocket@0.11.1 | MIT | https://github.com/faye/faye-websocket-node | +| file-loader@1.1.11 | MIT | https://github.com/webpack/file-loader/raw/master/LICENSE | +| filename-regex@2.0.1 | MIT | https://github.com/regexhq/filename-regex/raw/master/LICENSE | +| fileset@2.0.3 | MIT | https://github.com/mklabs/node-fileset/raw/master/LICENSE-MIT | +| fill-range@2.2.4 | MIT | https://github.com/jonschlinkert/fill-range/raw/master/LICENSE | +| fill-range@4.0.0 | MIT | https://github.com/jonschlinkert/fill-range/raw/master/LICENSE | +| finalhandler@1.1.0 | MIT | https://github.com/pillarjs/finalhandler/raw/master/LICENSE | +| finalhandler@1.1.1 | MIT | https://github.com/pillarjs/finalhandler/raw/master/LICENSE | +| find-cache-dir@1.0.0 | MIT | https://github.com/avajs/find-cache-dir/raw/master/license | +| find-up@1.1.2 | MIT | https://github.com/sindresorhus/find-up/raw/master/license | +| find-up@2.1.0 | MIT | https://github.com/sindresorhus/find-up/raw/master/license | +| flush-write-stream@1.0.3 | MIT | https://github.com/mafintosh/flush-write-stream/raw/master/LICENSE | +| follow-redirects@1.5.0 | MIT | https://github.com/olalonde/follow-redirects/raw/master/LICENSE | +| for-in@0.1.8 | MIT | https://github.com/jonschlinkert/for-in/raw/master/LICENSE | +| for-in@1.0.2 | MIT | https://github.com/jonschlinkert/for-in/raw/master/LICENSE | +| for-own@0.1.5 | MIT | https://github.com/jonschlinkert/for-own/raw/master/LICENSE | +| for-own@1.0.0 | MIT | https://github.com/jonschlinkert/for-own/raw/master/LICENSE | +| foreach@2.0.5 | MIT | https://github.com/manuelstofer/foreach/raw/master/LICENSE | +| forever-agent@0.6.1 | Apache-2.0 | https://github.com/mikeal/forever-agent/raw/master/LICENSE | +| form-data@2.1.4 | MIT | https://github.com/form-data/form-data/raw/master/License | +| form-data@2.3.2 | MIT | https://github.com/form-data/form-data/raw/master/License | +| forwarded@0.1.2 | MIT | https://github.com/jshttp/forwarded/raw/master/LICENSE | +| fragment-cache@0.2.1 | MIT | https://github.com/jonschlinkert/fragment-cache/raw/master/LICENSE | +| fresh@0.5.2 | MIT | https://github.com/jshttp/fresh/raw/master/LICENSE | +| from2@2.3.0 | MIT | https://github.com/hughsk/from2/raw/master/LICENSE.md | +| fs-access@1.0.1 | MIT | https://github.com/sindresorhus/fs-access/raw/master/license | +| fs-minipass@1.2.5 | ISC | https://github.com/npm/fs-minipass/raw/master/LICENSE | +| fs-write-stream-atomic@1.0.10 | ISC | https://github.com/npm/fs-write-stream-atomic/raw/master/LICENSE | +| fs.realpath@1.0.0 | ISC | https://github.com/isaacs/fs.realpath/raw/master/LICENSE | +| fsevents@1.2.4 | MIT | https://github.com/strongloop/fsevents/raw/master/LICENSE | +| fstream@1.0.11 | ISC | https://github.com/npm/fstream/raw/master/LICENSE | +| function-bind@1.1.1 | MIT | https://github.com/Raynos/function-bind/raw/master/LICENSE | +| gauge@2.7.4 | ISC | https://github.com/iarna/gauge/raw/master/LICENSE | +| gaze@1.1.3 | MIT | https://github.com/shama/gaze/raw/master/LICENSE-MIT | +| generate-function@2.0.0 | MIT | https://github.com/mafintosh/generate-function | +| generate-object-property@1.2.0 | MIT | https://github.com/mafintosh/generate-object-property/raw/master/LICENSE | +| get-caller-file@1.0.2 | ISC | https://github.com/stefanpenner/get-caller-file | +| get-stdin@4.0.1 | MIT | https://github.com/sindresorhus/get-stdin | +| get-stream@3.0.0 | MIT | https://github.com/sindresorhus/get-stream/raw/master/license | +| get-value@2.0.6 | MIT | https://github.com/jonschlinkert/get-value/raw/master/LICENSE | +| getpass@0.1.7 | MIT | https://github.com/arekinath/node-getpass/raw/master/LICENSE | +| glob-base@0.3.0 | MIT | https://github.com/jonschlinkert/glob-base/blob/master/LICENSE | +| glob-parent@2.0.0 | ISC | https://github.com/es128/glob-parent/raw/master/LICENSE | +| glob-parent@3.1.0 | ISC | https://github.com/es128/glob-parent/raw/master/LICENSE | +| glob@5.0.15 | ISC | https://github.com/isaacs/node-glob/raw/master/LICENSE | +| glob@6.0.4 | ISC | https://github.com/isaacs/node-glob/raw/master/LICENSE | +| glob@7.0.6 | ISC | https://github.com/isaacs/node-glob/raw/master/LICENSE | +| glob@7.1.2 | ISC | https://github.com/isaacs/node-glob/raw/master/LICENSE | +| globals@9.18.0 | MIT | https://github.com/sindresorhus/globals/raw/master/license | +| globby@5.0.0 | MIT | https://github.com/sindresorhus/globby/raw/master/license | +| globby@6.1.0 | MIT | https://github.com/sindresorhus/globby/raw/master/license | +| globby@7.1.1 | MIT | https://github.com/sindresorhus/globby/raw/master/license | +| globule@1.2.1 | MIT | https://github.com/cowboy/node-globule/raw/master/LICENSE | +| graceful-fs@4.1.11 | ISC | https://github.com/isaacs/node-graceful-fs/raw/master/LICENSE | +| handle-thing@1.2.5 | MIT | https://github.com/indutny/handle-thing | +| handlebars@4.0.11 | MIT | https://github.com/wycats/handlebars.js/raw/master/LICENSE | +| har-schema@2.0.0 | ISC | https://github.com/ahmadnassri/har-schema/raw/master/LICENSE | +| har-validator@2.0.6 | ISC | https://github.com/ahmadnassri/har-validator/raw/master/LICENSE | +| har-validator@5.0.3 | ISC | https://github.com/ahmadnassri/har-validator/raw/master/LICENSE | +| has-ansi@2.0.0 | MIT | https://github.com/sindresorhus/has-ansi/raw/master/license | +| has-binary@0.1.7 | MIT | | +| has-cors@1.1.0 | MIT | https://github.com/component/has-cors | +| has-flag@1.0.0 | MIT | https://github.com/sindresorhus/has-flag/raw/master/license | +| has-flag@2.0.0 | MIT | https://github.com/sindresorhus/has-flag/raw/master/license | +| has-flag@3.0.0 | MIT | https://github.com/sindresorhus/has-flag/raw/master/license | +| has-symbols@1.0.0 | MIT | https://github.com/ljharb/has-symbols/raw/master/LICENSE | +| has-unicode@2.0.1 | ISC | https://github.com/iarna/has-unicode/raw/master/LICENSE | +| has-value@0.3.1 | MIT | https://github.com/jonschlinkert/has-value/raw/master/LICENSE | +| has-value@1.0.0 | MIT | https://github.com/jonschlinkert/has-value/raw/master/LICENSE | +| has-values@0.1.4 | MIT | https://github.com/jonschlinkert/has-values/raw/master/LICENSE | +| has-values@1.0.0 | MIT | https://github.com/jonschlinkert/has-values/raw/master/LICENSE | +| has@1.0.3 | MIT | https://github.com/tarruda/has/raw/master/LICENSE-MIT | +| hash-base@3.0.4 | MIT | https://github.com/crypto-browserify/hash-base/raw/master/LICENSE | +| hash.js@1.1.3 | MIT | https://github.com/indutny/hash.js | +| hawk@3.1.3 | BSD-3-Clause | https://github.com/hueniverse/hawk/raw/master/LICENSE | +| he@1.1.1 | MIT | https://github.com/mathiasbynens/he/raw/master/LICENSE-MIT.txt | +| hmac-drbg@1.0.1 | MIT | https://github.com/indutny/hmac-drbg | +| hoek@2.16.3 | BSD-3-Clause | https://github.com/hapijs/hoek/raw/master/LICENSE | +| hosted-git-info@2.6.0 | ISC | https://github.com/npm/hosted-git-info/raw/master/LICENSE | +| hpack.js@2.1.6 | MIT | https://github.com/indutny/hpack.js | +| html-entities@1.2.1 | MIT | https://github.com/mdevils/node-html-entities/raw/master/LICENSE | +| html-minifier@3.5.16 | MIT | https://github.com/kangax/html-minifier/raw/master/LICENSE | +| html-webpack-plugin@3.2.0 | MIT | https://github.com/jantimon/html-webpack-plugin/raw/master/LICENSE | +| htmlparser2@3.3.0 | MIT | http://github.com/fb55/htmlparser2/raw/master/LICENSE | +| http-deceiver@1.2.7 | MIT | https://github.com/indutny/http-deceiver | +| http-errors@1.6.2 | MIT | https://github.com/jshttp/http-errors/raw/master/LICENSE | +| http-errors@1.6.3 | MIT | https://github.com/jshttp/http-errors/raw/master/LICENSE | +| http-parser-js@0.4.13 | MIT | https://github.com/creationix/http-parser-js/raw/master/LICENSE.md | +| http-proxy-middleware@0.18.0 | MIT | https://github.com/chimurai/http-proxy-middleware/raw/master/LICENSE | +| http-proxy@1.17.0 | MIT | https://github.com/nodejitsu/node-http-proxy/raw/master/LICENSE | +| http-signature@1.1.1 | MIT | https://github.com/joyent/node-http-signature/raw/master/LICENSE | +| http-signature@1.2.0 | MIT | https://github.com/joyent/node-http-signature/raw/master/LICENSE | +| https-browserify@1.0.0 | MIT | https://github.com/substack/https-browserify/raw/master/LICENSE | +| https-proxy-agent@2.2.1 | MIT | https://github.com/TooTallNate/node-https-proxy-agent | +| iconv-lite@0.4.19 | MIT | https://github.com/ashtuchkin/iconv-lite/raw/master/LICENSE | +| iconv-lite@0.4.21 | MIT | https://github.com/ashtuchkin/iconv-lite/raw/master/LICENSE | +| ieee754@1.1.11 | BSD-3-Clause | https://github.com/feross/ieee754/raw/master/LICENSE | +| iferr@0.1.5 | MIT | https://github.com/shesek/iferr/raw/master/LICENSE | +| ignore-walk@3.0.1 | ISC | https://github.com/isaacs/ignore-walk/raw/master/LICENSE | +| ignore@3.3.8 | MIT | https://github.com/kaelzhang/node-ignore | +| image-size@0.5.5 | MIT | https://github.com/image-size/image-size/raw/master/LICENSE | +| immediate@3.0.6 | MIT | https://github.com/calvinmetcalf/immediate/raw/master/LICENSE.txt | +| import-local@1.0.0 | MIT | https://github.com/sindresorhus/import-local/raw/master/license | +| imurmurhash@0.1.4 | MIT | https://github.com/jensyt/imurmurhash-js | +| in-publish@2.0.0 | ISC | https://github.com/iarna/in-publish/raw/master/LICENSE | +| indent-string@2.1.0 | MIT | https://github.com/sindresorhus/indent-string/raw/master/license | +| indexof@0.0.1 | MIT* | https://github.com/component/indexof/raw/master/LICENSE | +| inflight@1.0.6 | ISC | https://github.com/npm/inflight/raw/master/LICENSE | +| inherits@2.0.1 | ISC | https://github.com/isaacs/inherits/raw/master/LICENSE | +| inherits@2.0.3 | ISC | https://github.com/isaacs/inherits/raw/master/LICENSE | +| ini@1.3.5 | ISC | https://github.com/isaacs/ini/raw/master/LICENSE | +| internal-ip@1.2.0 | MIT | https://github.com/sindresorhus/internal-ip/raw/master/license | +| invariant@2.2.4 | MIT | https://github.com/zertosh/invariant/raw/master/LICENSE | +| invert-kv@1.0.0 | MIT | https://github.com/sindresorhus/invert-kv | +| ip@1.1.5 | MIT | http://github.com/indutny/node-ip | +| ipaddr.js@1.6.0 | MIT | https://github.com/whitequark/ipaddr.js/raw/master/LICENSE | +| is-accessor-descriptor@0.1.6 | MIT | https://github.com/jonschlinkert/is-accessor-descriptor/raw/master/LICENSE | +| is-accessor-descriptor@1.0.0 | MIT | https://github.com/jonschlinkert/is-accessor-descriptor/raw/master/LICENSE | +| is-arrayish@0.2.1 | MIT | https://github.com/qix-/node-is-arrayish/raw/master/LICENSE | +| is-binary-path@1.0.1 | MIT | https://github.com/sindresorhus/is-binary-path/raw/master/license | +| is-buffer@1.1.6 | MIT | https://github.com/feross/is-buffer/raw/master/LICENSE | +| is-builtin-module@1.0.0 | MIT | https://github.com/sindresorhus/is-builtin-module/raw/master/license | +| is-callable@1.1.3 | MIT | https://github.com/ljharb/is-callable/raw/master/LICENSE | +| is-data-descriptor@0.1.4 | MIT | https://github.com/jonschlinkert/is-data-descriptor/raw/master/LICENSE | +| is-data-descriptor@1.0.0 | MIT | https://github.com/jonschlinkert/is-data-descriptor/raw/master/LICENSE | +| is-date-object@1.0.1 | MIT | https://github.com/ljharb/is-date-object/raw/master/LICENSE | +| is-descriptor@0.1.6 | MIT | https://github.com/jonschlinkert/is-descriptor/raw/master/LICENSE | +| is-descriptor@1.0.2 | MIT | https://github.com/jonschlinkert/is-descriptor/raw/master/LICENSE | +| is-directory@0.3.1 | MIT | https://github.com/jonschlinkert/is-directory/raw/master/LICENSE | +| is-dotfile@1.0.3 | MIT | https://github.com/jonschlinkert/is-dotfile/raw/master/LICENSE | +| is-equal-shallow@0.1.3 | MIT | https://github.com/jonschlinkert/is-equal-shallow/raw/master/LICENSE | +| is-extendable@0.1.1 | MIT | https://github.com/jonschlinkert/is-extendable/raw/master/LICENSE | +| is-extendable@1.0.1 | MIT | https://github.com/jonschlinkert/is-extendable/raw/master/LICENSE | +| is-extglob@1.0.0 | MIT | https://github.com/jonschlinkert/is-extglob/raw/master/LICENSE | +| is-extglob@2.1.1 | MIT | https://github.com/jonschlinkert/is-extglob/raw/master/LICENSE | +| is-finite@1.0.2 | MIT | https://github.com/sindresorhus/is-finite/raw/master/license | +| is-fullwidth-code-point@1.0.0 | MIT | https://github.com/sindresorhus/is-fullwidth-code-point/raw/master/license | +| is-fullwidth-code-point@2.0.0 | MIT | https://github.com/sindresorhus/is-fullwidth-code-point/raw/master/license | +| is-glob@2.0.1 | MIT | https://github.com/jonschlinkert/is-glob/raw/master/LICENSE | +| is-glob@3.1.0 | MIT | https://github.com/jonschlinkert/is-glob/raw/master/LICENSE | +| is-glob@4.0.0 | MIT | https://github.com/jonschlinkert/is-glob/raw/master/LICENSE | +| is-my-ip-valid@1.0.0 | MIT | https://github.com/LinusU/is-my-ip-valid | +| is-my-json-valid@2.17.2 | MIT | https://github.com/mafintosh/is-my-json-valid/raw/master/LICENSE | +| is-number@0.1.1 | MIT | https://github.com/jonschlinkert/is-number/blob/master/LICENSE-MIT | +| is-number@2.1.0 | MIT | https://github.com/jonschlinkert/is-number/raw/master/LICENSE | +| is-number@3.0.0 | MIT | https://github.com/jonschlinkert/is-number/raw/master/LICENSE | +| is-number@4.0.0 | MIT | https://github.com/jonschlinkert/is-number/raw/master/LICENSE | +| is-odd@2.0.0 | MIT | https://github.com/jonschlinkert/is-odd/raw/master/LICENSE | +| is-path-cwd@1.0.0 | MIT | https://github.com/sindresorhus/is-path-cwd | +| is-path-in-cwd@1.0.1 | MIT | https://github.com/sindresorhus/is-path-in-cwd/raw/master/license | +| is-path-inside@1.0.1 | MIT | https://github.com/sindresorhus/is-path-inside/raw/master/license | +| is-plain-object@2.0.4 | MIT | https://github.com/jonschlinkert/is-plain-object/raw/master/LICENSE | +| is-posix-bracket@0.1.1 | MIT | https://github.com/jonschlinkert/is-posix-bracket/raw/master/LICENSE | +| is-primitive@2.0.0 | MIT | https://github.com/jonschlinkert/is-primitive/blob/master/LICENSE | +| is-property@1.0.2 | MIT | https://github.com/mikolalysenko/is-property/raw/master/LICENSE | +| is-regex@1.0.4 | MIT | https://github.com/ljharb/is-regex/raw/master/LICENSE | +| is-stream@1.1.0 | MIT | https://github.com/sindresorhus/is-stream/raw/master/license | +| is-symbol@1.0.1 | MIT | https://github.com/ljharb/is-symbol/raw/master/LICENSE | +| is-typedarray@1.0.0 | MIT | https://github.com/hughsk/is-typedarray/raw/master/LICENSE.md | +| is-utf8@0.2.1 | MIT | https://github.com/wayfind/is-utf8/raw/master/LICENSE | +| is-windows@1.0.2 | MIT | https://github.com/jonschlinkert/is-windows/raw/master/LICENSE | +| is-wsl@1.1.0 | MIT | https://github.com/sindresorhus/is-wsl/raw/master/license | +| isarray@0.0.1 | MIT | https://github.com/juliangruber/isarray | +| isarray@1.0.0 | MIT | https://github.com/juliangruber/isarray | +| isbinaryfile@3.0.2 | MIT | https://github.com/gjtorikian/isBinaryFile/raw/master/LICENSE.txt | +| isexe@2.0.0 | ISC | https://github.com/isaacs/isexe/raw/master/LICENSE | +| isobject@2.1.0 | MIT | https://github.com/jonschlinkert/isobject/raw/master/LICENSE | +| isobject@3.0.1 | MIT | https://github.com/jonschlinkert/isobject/raw/master/LICENSE | +| isstream@0.1.2 | MIT | https://github.com/rvagg/isstream/raw/master/LICENSE.md | +| istanbul-api@1.3.1 | BSD-3-Clause | https://github.com/istanbuljs/istanbuljs/raw/master/LICENSE | +| istanbul-instrumenter-loader@3.0.1 | MIT | https://github.com/webpack-contrib/istanbul-instrumenter-loader/raw/master/LICENSE | +| istanbul-lib-coverage@1.2.0 | BSD-3-Clause | https://github.com/istanbuljs/istanbuljs/raw/master/LICENSE | +| istanbul-lib-hook@1.2.1 | BSD-3-Clause | https://github.com/istanbuljs/istanbuljs/raw/master/LICENSE | +| istanbul-lib-instrument@1.10.1 | BSD-3-Clause | https://github.com/istanbuljs/istanbuljs/raw/master/LICENSE | +| istanbul-lib-report@1.1.4 | BSD-3-Clause | https://github.com/istanbuljs/istanbuljs/raw/master/LICENSE | +| istanbul-lib-source-maps@1.2.5 | BSD-3-Clause | https://github.com/istanbuljs/istanbuljs/raw/master/LICENSE | +| istanbul-reports@1.3.0 | BSD-3-Clause | https://github.com/istanbuljs/istanbuljs/raw/master/LICENSE | +| istanbul@0.4.5 | BSD-3-Clause | https://github.com/gotwarlost/istanbul/raw/master/LICENSE | +| jasmine-core@2.8.0 | MIT | https://github.com/jasmine/jasmine/raw/master/MIT.LICENSE | +| jasmine-core@2.99.1 | MIT | https://github.com/jasmine/jasmine/raw/master/MIT.LICENSE | +| jasmine-spec-reporter@4.2.1 | Apache-2.0 | https://github.com/bcaudan/jasmine-spec-reporter/raw/master/LICENSE | +| jasmine@2.8.0 | MIT | https://github.com/jasmine/jasmine-npm/raw/master/MIT.LICENSE | +| jasminewd2@2.2.0 | MIT | https://github.com/angular/jasminewd/raw/master/LICENSE | +| js-base64@2.4.5 | BSD-3-Clause | https://github.com/dankogai/js-base64/raw/master/LICENSE.md | +| js-tokens@3.0.2 | MIT | https://github.com/lydell/js-tokens/raw/master/LICENSE | +| js-yaml@3.12.0 | MIT | https://github.com/nodeca/js-yaml/raw/master/LICENSE | +| jsbn@0.1.1 | MIT | https://github.com/andyperlitch/jsbn/raw/master/LICENSE | +| jsesc@0.5.0 | MIT | http://mths.be/mit | +| jsesc@1.3.0 | MIT | https://github.com/mathiasbynens/jsesc/raw/master/LICENSE-MIT.txt | +| json-schema-traverse@0.3.1 | MIT | https://github.com/epoberezkin/json-schema-traverse/raw/master/LICENSE | +| json-schema@0.2.3 | AFLv2.1,BSD | http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L43,http://trac.dojotoolkit.org/browser/dojo/trunk/LICENSE#L13 | +| json-stringify-safe@5.0.1 | ISC | https://github.com/isaacs/json-stringify-safe/raw/master/LICENSE | +| json3@3.3.2 | MIT | http://kit.mit-license.org/ | +| json5@0.5.1 | MIT | https://github.com/aseemk/json5/raw/master/LICENSE.md | +| jsonpointer@4.0.1 | MIT | http://github.com/janl/node-jsonpointer/raw/master/LICENSE.md | +| jsprim@1.4.1 | MIT | https://github.com/joyent/node-jsprim/raw/master/LICENSE | +| jszip@3.1.5 | (MIT OR GPL-3.0) | https://github.com/Stuk/jszip/raw/master/LICENSE.markdown | +| karma-chrome-launcher@2.2.0 | MIT | https://github.com/karma-runner/karma-chrome-launcher/raw/master/LICENSE | +| karma-coverage-istanbul-reporter@2.0.1 | MIT | https://github.com/mattlewis92/karma-coverage-istanbul-reporter/raw/master/LICENSE | +| karma-jasmine-html-reporter@0.2.2 | MIT | https://github.com/taras42/karma-jasmine-html-reporter/raw/master/LICENSE | +| karma-jasmine@1.1.2 | MIT | https://github.com/karma-runner/karma-jasmine/raw/master/LICENSE | +| karma-source-map-support@1.3.0 | MIT | https://github.com/tschaub/karma-source-map-support | +| karma@1.7.1 | MIT | https://github.com/karma-runner/karma/raw/master/LICENSE | +| killable@1.0.0 | ISC | https://github.com/marten-de-vries/killable | +| kind-of@3.2.2 | MIT | https://github.com/jonschlinkert/kind-of/raw/master/LICENSE | +| kind-of@4.0.0 | MIT | https://github.com/jonschlinkert/kind-of/raw/master/LICENSE | +| kind-of@5.1.0 | MIT | https://github.com/jonschlinkert/kind-of/raw/master/LICENSE | +| kind-of@6.0.2 | MIT | https://github.com/jonschlinkert/kind-of/raw/master/LICENSE | +| lazy-cache@1.0.4 | MIT | https://github.com/jonschlinkert/lazy-cache/raw/master/LICENSE | +| lcid@1.0.0 | MIT | https://github.com/sindresorhus/lcid/raw/master/license | +| leb@0.3.0 | Apache 2.0 | http://www.apache.org/licenses/LICENSE-2.0.html | +| less-loader@4.1.0 | MIT | https://github.com/webpack-contrib/less-loader/raw/master/LICENSE | +| less@3.0.4 | Apache-2.0 | https://github.com/less/less.js/raw/master/LICENSE | +| levn@0.3.0 | MIT | https://github.com/gkz/levn/raw/master/LICENSE | +| license-webpack-plugin@1.3.1 | ISC | https://github.com/xz64/license-webpack-plugin/raw/master/LICENSE | +| lie@3.1.1 | MIT | https://github.com/calvinmetcalf/lie/raw/master/license.md | +| load-json-file@1.1.0 | MIT | https://github.com/sindresorhus/load-json-file/raw/master/license | +| loader-runner@2.3.0 | MIT | https://github.com/webpack/loader-runner | +| loader-utils@0.2.17 | MIT | https://github.com/webpack/loader-utils/raw/master/LICENSE | +| loader-utils@1.1.0 | MIT | https://github.com/webpack/loader-utils/raw/master/LICENSE | +| locate-path@2.0.0 | MIT | https://github.com/sindresorhus/locate-path/raw/master/license | +| lodash.assign@4.2.0 | MIT | https://github.com/lodash/lodash/raw/master/LICENSE | +| lodash.clonedeep@4.5.0 | MIT | https://github.com/lodash/lodash/raw/master/LICENSE | +| lodash.mergewith@4.6.1 | MIT | https://github.com/lodash/lodash/raw/master/LICENSE | +| lodash.tail@4.1.1 | MIT | https://github.com/lodash/lodash/raw/master/LICENSE | +| lodash@3.10.1 | MIT | https://github.com/lodash/lodash/raw/master/LICENSE | +| lodash@4.17.10 | MIT | https://github.com/lodash/lodash/raw/master/LICENSE | +| log-symbols@2.2.0 | MIT | https://github.com/sindresorhus/log-symbols/raw/master/license | +| log4js@0.6.38 | Apache-2.0 | https://github.com/nomiddlename/log4js-node/raw/master/LICENSE | +| loglevel@1.6.1 | MIT | https://github.com/pimterry/loglevel/raw/master/LICENSE-MIT | +| loglevelnext@1.0.5 | MIT | https://github.com/shellscape/loglevelnext/raw/master/LICENSE | +| long@3.2.0 | Apache-2.0 | https://github.com/dcodeIO/long.js/raw/master/LICENSE | +| longest@1.0.1 | MIT | https://github.com/jonschlinkert/longest/blob/master/LICENSE | +| loose-envify@1.3.1 | MIT | https://github.com/zertosh/loose-envify/raw/master/LICENSE | +| loud-rejection@1.6.0 | MIT | https://github.com/sindresorhus/loud-rejection/raw/master/license | +| lower-case@1.1.4 | MIT | https://github.com/blakeembrey/lower-case/raw/master/LICENSE | +| lru-cache@4.1.3 | ISC | https://github.com/isaacs/node-lru-cache/raw/master/LICENSE | +| make-dir@1.3.0 | MIT | https://github.com/sindresorhus/make-dir/raw/master/license | +| make-error@1.3.4 | ISC | https://github.com/JsCommunity/make-error | +| map-cache@0.2.2 | MIT | https://github.com/jonschlinkert/map-cache/raw/master/LICENSE | +| map-obj@1.0.1 | MIT | https://github.com/sindresorhus/map-obj/raw/master/license | +| map-visit@1.0.0 | MIT | https://github.com/jonschlinkert/map-visit/raw/master/LICENSE | +| math-random@1.0.1 | MIT | https://github.com/michaelrhodes/math-random | +| md5.js@1.3.4 | MIT | https://github.com/crypto-browserify/md5.js/raw/master/LICENSE | +| media-typer@0.3.0 | MIT | https://github.com/jshttp/media-typer/raw/master/LICENSE | +| mem@1.1.0 | MIT | https://github.com/sindresorhus/mem/raw/master/license | +| memory-fs@0.4.1 | MIT | https://github.com/webpack/memory-fs | +| meow@3.7.0 | MIT | https://github.com/sindresorhus/meow/raw/master/license | +| merge-descriptors@1.0.1 | MIT | https://github.com/component/merge-descriptors/raw/master/LICENSE | +| methods@1.1.2 | MIT | https://github.com/jshttp/methods/raw/master/LICENSE | +| micromatch@2.3.11 | MIT | https://github.com/jonschlinkert/micromatch/raw/master/LICENSE | +| micromatch@3.1.10 | MIT | https://github.com/micromatch/micromatch/raw/master/LICENSE | +| miller-rabin@4.0.1 | MIT | https://github.com/indutny/miller-rabin | +| mime-db@1.33.0 | MIT | https://github.com/jshttp/mime-db/raw/master/LICENSE | +| mime-db@1.34.0 | MIT | https://github.com/jshttp/mime-db/raw/master/LICENSE | +| mime-types@2.1.18 | MIT | https://github.com/jshttp/mime-types/raw/master/LICENSE | +| mime@1.4.1 | MIT | https://github.com/broofa/node-mime/raw/master/LICENSE | +| mime@1.6.0 | MIT | https://github.com/broofa/node-mime/raw/master/LICENSE | +| mime@2.3.1 | MIT | https://github.com/broofa/node-mime/raw/master/LICENSE | +| mimic-fn@1.2.0 | MIT | https://github.com/sindresorhus/mimic-fn/raw/master/license | +| mini-css-extract-plugin@0.4.0 | MIT | https://github.com/webpack-contrib/mini-css-extract-plugin/raw/master/LICENSE | +| minimalistic-assert@1.0.1 | ISC | https://github.com/calvinmetcalf/minimalistic-assert/raw/master/LICENSE | +| minimalistic-crypto-utils@1.0.1 | MIT | https://github.com/indutny/minimalistic-crypto-utils | +| minimatch@3.0.4 | ISC | https://github.com/isaacs/minimatch/raw/master/LICENSE | +| minimist@0.0.8 | MIT | https://github.com/substack/minimist/raw/master/LICENSE | +| minimist@1.2.0 | MIT | https://github.com/substack/minimist/raw/master/LICENSE | +| minipass@2.2.4 | ISC | https://github.com/isaacs/minipass | +| minizlib@1.1.0 | MIT | https://github.com/isaacs/minizlib/raw/master/LICENSE | +| mississippi@2.0.0 | BSD-2-Clause | https://github.com/maxogden/mississippi/raw/master/license | +| mixin-deep@1.3.1 | MIT | https://github.com/jonschlinkert/mixin-deep/raw/master/LICENSE | +| mixin-object@2.0.1 | MIT | https://github.com/jonschlinkert/mixin-object/raw/master/LICENSE | +| mkdirp@0.5.1 | MIT | https://github.com/substack/node-mkdirp/raw/master/LICENSE | +| moment@2.22.2 | MIT | https://github.com/moment/moment/raw/master/LICENSE | +| move-concurrently@1.0.1 | ISC | https://github.com/npm/move-concurrently/raw/master/LICENSE | +| ms@0.7.1 | MIT* | https://github.com/guille/ms.js/raw/master/LICENSE | +| ms@0.7.2 | MIT | https://github.com/zeit/ms/raw/master/LICENSE.md | +| ms@2.0.0 | MIT | https://github.com/zeit/ms/raw/master/license.md | +| multicast-dns-service-types@1.1.0 | MIT | https://github.com/mafintosh/multicast-dns-service-types/raw/master/LICENSE | +| multicast-dns@6.2.3 | MIT | https://github.com/mafintosh/multicast-dns/raw/master/LICENSE | +| nan@2.10.0 | MIT | https://github.com/nodejs/nan/raw/master/LICENSE.md | +| nanomatch@1.2.9 | MIT | https://github.com/micromatch/nanomatch/raw/master/LICENSE | +| needle@2.2.0 | MIT | https://github.com/tomas/needle/raw/master/license.txt | +| negotiator@0.6.1 | MIT | https://github.com/jshttp/negotiator/raw/master/LICENSE | +| neo-async@2.5.1 | MIT | https://github.com/suguru03/neo-async | +| next-tick@1.0.0 | MIT | https://github.com/medikoo/next-tick/raw/master/LICENSE | +| ng-inline-svg@8.0.0 | MIT | https://github.com/arkon/ng-inline-svg/raw/master/LICENSE | +| ngx-cookie-service@1.0.10 | MIT | https://github.com/7leads/ngx-cookie-service | +| ngx-slimscroll@7.1.0 | MIT | https://github.com/jkuri/ngx-slimscroll/raw/master/LICENSE | +| no-case@2.3.2 | MIT | https://github.com/blakeembrey/no-case/raw/master/LICENSE | +| node-forge@0.7.5 | (BSD-3-Clause OR GPL-2.0) | https://github.com/digitalbazaar/forge/raw/master/LICENSE | +| node-gyp@3.6.2 | MIT | https://github.com/nodejs/node-gyp/raw/master/LICENSE | +| node-libs-browser@2.1.0 | MIT | https://github.com/webpack/node-libs-browser/raw/master/LICENSE | +| node-pre-gyp@0.10.0 | BSD-3-Clause | https://github.com/mapbox/node-pre-gyp/raw/master/LICENSE | +| node-sass@4.9.0 | MIT | https://github.com/sass/node-sass/raw/master/LICENSE | +| nopt@3.0.6 | ISC | https://github.com/npm/nopt/raw/master/LICENSE | +| nopt@4.0.1 | ISC | https://github.com/npm/nopt/raw/master/LICENSE | +| normalize-package-data@2.4.0 | BSD-2-Clause | https://github.com/npm/normalize-package-data/raw/master/LICENSE | +| normalize-path@2.1.1 | MIT | https://github.com/jonschlinkert/normalize-path/raw/master/LICENSE | +| normalize-range@0.1.2 | MIT | https://github.com/jamestalmage/normalize-range/raw/master/license | +| npm-bundled@1.0.3 | ISC | https://github.com/npm/npm-bundled | +| npm-package-arg@6.1.0 | ISC | https://github.com/npm/npm-package-arg/raw/master/LICENSE | +| npm-packlist@1.1.10 | ISC | https://github.com/npm/npm-packlist/raw/master/LICENSE | +| npm-registry-client@8.5.1 | ISC | https://github.com/npm/npm-registry-client/raw/master/LICENSE | +| npm-run-path@2.0.2 | MIT | https://github.com/sindresorhus/npm-run-path/raw/master/license | +| npmlog@4.1.2 | ISC | https://github.com/npm/npmlog/raw/master/LICENSE | +| nth-check@1.0.1 | BSD | https://github.com/fb55/nth-check | +| null-check@1.0.0 | MIT | https://github.com/sindresorhus/null-check/raw/master/license | +| num2fraction@1.2.2 | MIT | https://github.com/yisibl/num2fraction/raw/master/LICENSE | +| number-is-nan@1.0.1 | MIT | https://github.com/sindresorhus/number-is-nan/raw/master/license | +| oauth-sign@0.8.2 | Apache-2.0 | https://github.com/mikeal/oauth-sign/raw/master/LICENSE | +| object-assign@4.1.0 | MIT | https://github.com/sindresorhus/object-assign/raw/master/license | +| object-assign@4.1.1 | MIT | https://github.com/sindresorhus/object-assign/raw/master/license | +| object-component@0.0.3 | MIT* | https://github.com/component/object/raw/master/LICENSE | +| object-copy@0.1.0 | MIT | https://github.com/jonschlinkert/object-copy/raw/master/LICENSE | +| object-keys@1.0.11 | MIT | https://github.com/ljharb/object-keys/raw/master/LICENSE | +| object-visit@1.0.1 | MIT | https://github.com/jonschlinkert/object-visit/raw/master/LICENSE | +| object.assign@4.1.0 | MIT | https://github.com/ljharb/object.assign/raw/master/LICENSE | +| object.getownpropertydescriptors@2.0.3 | MIT | https://github.com/ljharb/object.getownpropertydescriptors/raw/master/LICENSE | +| object.omit@2.0.1 | MIT | https://github.com/jonschlinkert/object.omit/raw/master/LICENSE | +| object.pick@1.3.0 | MIT | https://github.com/jonschlinkert/object.pick/raw/master/LICENSE | +| obuf@1.1.2 | MIT | https://github.com/indutny/offset-buffer/raw/master/LICENSE | +| on-finished@2.3.0 | MIT | https://github.com/jshttp/on-finished/raw/master/LICENSE | +| on-headers@1.0.1 | MIT | https://github.com/jshttp/on-headers/raw/master/LICENSE | +| once@1.4.0 | ISC | https://github.com/isaacs/once/raw/master/LICENSE | +| opn@5.3.0 | MIT | https://github.com/sindresorhus/opn/raw/master/license | +| optimist@0.6.1 | MIT/X11 | http://github.com/substack/node-optimist/raw/master/LICENSE | +| optionator@0.8.2 | MIT | https://github.com/gkz/optionator/raw/master/LICENSE | +| options@0.0.6 | MIT* | https://github.com/einaros/options.js/raw/master/README.md | +| original@1.0.1 | MIT | https://github.com/unshiftio/original/raw/master/LICENSE | +| os-browserify@0.3.0 | MIT | http://github.com/CoderPuppy/os-browserify/raw/master/LICENSE | +| os-homedir@1.0.2 | MIT | https://github.com/sindresorhus/os-homedir/raw/master/license | +| os-locale@1.4.0 | MIT | https://github.com/sindresorhus/os-locale/raw/master/license | +| os-locale@2.1.0 | MIT | https://github.com/sindresorhus/os-locale/raw/master/license | +| os-tmpdir@1.0.2 | MIT | https://github.com/sindresorhus/os-tmpdir/raw/master/license | +| osenv@0.1.5 | ISC | https://github.com/npm/osenv/raw/master/LICENSE | +| p-finally@1.0.0 | MIT | https://github.com/sindresorhus/p-finally/raw/master/license | +| p-limit@1.3.0 | MIT | https://github.com/sindresorhus/p-limit/raw/master/license | +| p-locate@2.0.0 | MIT | https://github.com/sindresorhus/p-locate/raw/master/license | +| p-map@1.2.0 | MIT | https://github.com/sindresorhus/p-map/raw/master/license | +| p-try@1.0.0 | MIT | https://github.com/sindresorhus/p-try/raw/master/license | +| pako@1.0.6 | (MIT AND Zlib) | https://github.com/nodeca/pako/raw/master/LICENSE | +| parallel-transform@1.1.0 | MIT | https://github.com/mafintosh/parallel-transform/raw/master/LICENSE | +| param-case@2.1.1 | MIT | https://github.com/blakeembrey/param-case/raw/master/LICENSE | +| parse-asn1@5.1.1 | ISC | https://github.com/crypto-browserify/parse-asn1/raw/master/LICENSE | +| parse-glob@3.0.4 | MIT | https://github.com/jonschlinkert/parse-glob/raw/master/LICENSE | +| parse-json@2.2.0 | MIT | https://github.com/sindresorhus/parse-json/raw/master/license | +| parse5@4.0.0 | MIT | https://github.com/inikulin/parse5/raw/master/LICENSE | +| parsejson@0.0.3 | MIT | https://github.com/get/parsejson/raw/master/LICENSE | +| parseqs@0.0.5 | MIT | https://github.com/get/querystring/raw/master/LICENSE | +| parseuri@0.0.5 | MIT | https://github.com/get/parseuri/raw/master/LICENSE | +| parseurl@1.3.2 | MIT | https://github.com/pillarjs/parseurl/raw/master/LICENSE | +| pascalcase@0.1.1 | MIT | https://github.com/jonschlinkert/pascalcase/raw/master/LICENSE | +| path-browserify@0.0.0 | MIT | https://github.com/substack/path-browserify/raw/master/LICENSE | +| path-dirname@1.0.2 | MIT | https://github.com/es128/path-dirname/raw/master/license | +| path-exists@2.1.0 | MIT | https://github.com/sindresorhus/path-exists/raw/master/license | +| path-exists@3.0.0 | MIT | https://github.com/sindresorhus/path-exists/raw/master/license | +| path-is-absolute@1.0.1 | MIT | https://github.com/sindresorhus/path-is-absolute/raw/master/license | +| path-is-inside@1.0.2 | (WTFPL OR MIT) | https://github.com/domenic/path-is-inside/raw/master/LICENSE.txt | +| path-key@2.0.1 | MIT | https://github.com/sindresorhus/path-key/raw/master/license | +| path-parse@1.0.5 | MIT | https://github.com/jbgutierrez/path-parse | +| path-to-regexp@0.1.7 | MIT | https://github.com/component/path-to-regexp/raw/master/LICENSE | +| path-type@1.1.0 | MIT | https://github.com/sindresorhus/path-type/raw/master/license | +| path-type@3.0.0 | MIT | https://github.com/sindresorhus/path-type/raw/master/license | +| pbkdf2@3.0.16 | MIT | https://github.com/crypto-browserify/pbkdf2/raw/master/LICENSE | +| performance-now@2.1.0 | MIT | https://github.com/braveg1rl/performance-now/raw/master/license.txt | +| pify@2.3.0 | MIT | https://github.com/sindresorhus/pify/raw/master/license | +| pify@3.0.0 | MIT | https://github.com/sindresorhus/pify/raw/master/license | +| pinkie-promise@2.0.1 | MIT | https://github.com/floatdrop/pinkie-promise/raw/master/license | +| pinkie@2.0.4 | MIT | https://github.com/floatdrop/pinkie/raw/master/license | +| pkg-dir@2.0.0 | MIT | https://github.com/sindresorhus/pkg-dir/raw/master/license | +| portfinder@1.0.13 | MIT | https://github.com/indexzero/node-portfinder/raw/master/LICENSE | +| posix-character-classes@0.1.1 | MIT | https://github.com/jonschlinkert/posix-character-classes/raw/master/LICENSE | +| postcss-import@11.1.0 | MIT | https://github.com/postcss/postcss-import/raw/master/LICENSE | +| postcss-load-config@1.2.0 | MIT | https://github.com/michael-ciniawsky/postcss-load-config/raw/master/LICENSE | +| postcss-load-options@1.2.0 | MIT | https://github.com/michael-ciniawsky/postcss-load-options/raw/master/LICENSE | +| postcss-load-plugins@2.3.0 | MIT | https://github.com/michael-ciniawsky/postcss-load-plugins/raw/master/LICENSE | +| postcss-loader@2.1.5 | MIT | https://github.com/postcss/postcss-loader/raw/master/LICENSE | +| postcss-url@7.3.2 | MIT | https://github.com/postcss/postcss-url/raw/master/LICENSE | +| postcss-value-parser@3.3.0 | MIT | https://github.com/TrySound/postcss-value-parser/raw/master/LICENSE | +| postcss@6.0.22 | MIT | https://github.com/postcss/postcss/raw/master/LICENSE | +| prelude-ls@1.1.2 | MIT | https://raw.github.com/gkz/prelude-ls/master/LICENSE | +| preserve@0.2.0 | MIT | https://github.com/jonschlinkert/preserve/blob/master/LICENSE-MIT | +| pretty-error@2.1.1 | MIT | https://github.com/AriaMinaei/pretty-error/raw/master/LICENSE | +| process-nextick-args@1.0.7 | MIT | https://github.com/calvinmetcalf/process-nextick-args/raw/master/license.md | +| process-nextick-args@2.0.0 | MIT | https://github.com/calvinmetcalf/process-nextick-args/raw/master/license.md | +| process@0.11.10 | MIT | https://github.com/shtylman/node-process/raw/master/LICENSE | +| promise-inflight@1.0.1 | ISC | https://github.com/iarna/promise-inflight/raw/master/LICENSE | +| promise@7.3.1 | MIT | https://github.com/then/promise/raw/master/LICENSE | +| protractor@5.3.2 | MIT | https://github.com/angular/protractor/raw/master/LICENSE | +| proxy-addr@2.0.3 | MIT | https://github.com/jshttp/proxy-addr/raw/master/LICENSE | +| prr@1.0.1 | MIT | https://github.com/rvagg/prr/raw/master/LICENSE.md | +| pseudomap@1.0.2 | ISC | https://github.com/isaacs/pseudomap/raw/master/LICENSE | +| public-encrypt@4.0.2 | MIT | https://github.com/crypto-browserify/publicEncrypt/raw/master/LICENSE | +| pump@2.0.1 | MIT | https://github.com/mafintosh/pump/raw/master/LICENSE | +| pumpify@1.5.1 | MIT | https://github.com/mafintosh/pumpify/raw/master/LICENSE | +| punycode@1.3.2 | MIT | https://github.com/bestiejs/punycode.js/raw/master/LICENSE-MIT.txt | +| punycode@1.4.1 | MIT | https://github.com/bestiejs/punycode.js/raw/master/LICENSE-MIT.txt | +| punycode@2.1.1 | MIT | https://github.com/bestiejs/punycode.js/raw/master/LICENSE-MIT.txt | +| q@1.4.1 | MIT | http://github.com/kriskowal/q/raw/master/LICENSE | +| qjobs@1.2.0 | MIT | https://github.com/franck34/qjobs/raw/master/LICENCE | +| qs@6.3.2 | BSD-3-Clause | https://github.com/ljharb/qs/raw/master/LICENSE | +| qs@6.5.1 | BSD-3-Clause | https://github.com/ljharb/qs/raw/master/LICENSE | +| qs@6.5.2 | BSD-3-Clause | https://github.com/ljharb/qs/raw/master/LICENSE | +| querystring-es3@0.2.1 | MIT | https://github.com/Gozala/enchain/License.md | +| querystring@0.2.0 | MIT | https://github.com/Gozala/enchain/License.md | +| querystringify@2.0.0 | MIT | https://github.com/unshiftio/querystringify/raw/master/LICENSE | +| randomatic@3.0.0 | MIT | https://github.com/jonschlinkert/randomatic/raw/master/LICENSE | +| randombytes@2.0.6 | MIT | https://github.com/crypto-browserify/randombytes/raw/master/LICENSE | +| randomfill@1.0.4 | MIT | https://github.com/crypto-browserify/randomfill/raw/master/LICENSE | +| range-parser@1.2.0 | MIT | https://github.com/jshttp/range-parser/raw/master/LICENSE | +| raw-body@2.3.2 | MIT | https://github.com/stream-utils/raw-body/raw/master/LICENSE | +| raw-loader@0.5.1 | MIT | http://www.opensource.org/licenses/mit-license.php | +| rc@1.2.7 | (BSD-2-Clause OR MIT OR Apache-2.0) | https://github.com/dominictarr/rc/raw/master/LICENSE.APACHE2 | +| read-cache@1.0.0 | MIT | https://github.com/TrySound/read-cache/raw/master/LICENSE | +| read-pkg-up@1.0.1 | MIT | https://github.com/sindresorhus/read-pkg-up/raw/master/license | +| read-pkg@1.1.0 | MIT | https://github.com/sindresorhus/read-pkg/raw/master/license | +| readable-stream@1.0.34 | MIT | https://github.com/isaacs/readable-stream/raw/master/LICENSE | +| readable-stream@2.0.6 | MIT | https://github.com/nodejs/readable-stream/raw/master/LICENSE | +| readable-stream@2.3.6 | MIT | https://github.com/nodejs/readable-stream/raw/master/LICENSE | +| readdirp@2.1.0 | MIT | https://github.com/thlorenz/readdirp/raw/master/LICENSE | +| redent@1.0.0 | MIT | https://github.com/sindresorhus/redent/raw/master/license | +| reflect-metadata@0.1.12 | Apache-2.0 | https://github.com/rbuckton/reflect-metadata/raw/master/LICENSE | +| regenerate@1.4.0 | MIT | https://github.com/mathiasbynens/regenerate/raw/master/LICENSE-MIT.txt | +| regenerator-runtime@0.11.1 | MIT | https://github.com/facebook/regenerator/tree/master/packages/regenerator-runtime | +| regex-cache@0.4.4 | MIT | https://github.com/jonschlinkert/regex-cache/raw/master/LICENSE | +| regex-not@1.0.2 | MIT | https://github.com/jonschlinkert/regex-not/raw/master/LICENSE | +| regexpu-core@1.0.0 | MIT | https://github.com/mathiasbynens/regexpu-core/raw/master/LICENSE-MIT.txt | +| regjsgen@0.2.0 | MIT | https://github.com/d10/regjsgen/raw/master/LICENSE.txt | +| regjsparser@0.1.5 | BSD | https://github.com/jviereck/regjsparser/raw/master/LICENSE.BSD | +| relateurl@0.2.7 | MIT | https://github.com/stevenvachon/relateurl/raw/master/license | +| remove-trailing-separator@1.1.0 | ISC | https://github.com/darsain/remove-trailing-separator/raw/master/license | +| renderkid@2.0.1 | MIT | https://github.com/AriaMinaei/RenderKid/raw/master/LICENSE | +| repeat-element@1.1.2 | MIT | https://github.com/jonschlinkert/repeat-element/blob/master/LICENSE | +| repeat-string@0.2.2 | MIT | https://github.com/jonschlinkert/repeat-string/blob/master/LICENSE-MIT | +| repeat-string@1.6.1 | MIT | https://github.com/jonschlinkert/repeat-string/raw/master/LICENSE | +| repeating@2.0.1 | MIT | https://github.com/sindresorhus/repeating/raw/master/license | +| request@2.79.0 | Apache-2.0 | https://github.com/request/request/raw/master/LICENSE | +| request@2.87.0 | Apache-2.0 | https://github.com/request/request/raw/master/LICENSE | +| require-directory@2.1.1 | MIT | https://github.com/troygoode/node-require-directory/raw/master/LICENSE | +| require-from-string@1.2.1 | MIT | https://github.com/floatdrop/require-from-string/raw/master/license | +| require-main-filename@1.0.1 | ISC | https://github.com/yargs/require-main-filename/raw/master/LICENSE.txt | +| requires-port@1.0.0 | MIT | https://github.com/unshiftio/requires-port/raw/master/LICENSE | +| resolve-cwd@2.0.0 | MIT | https://github.com/sindresorhus/resolve-cwd/raw/master/license | +| resolve-from@3.0.0 | MIT | https://github.com/sindresorhus/resolve-from/raw/master/license | +| resolve-url@0.2.1 | MIT | https://github.com/lydell/resolve-url/raw/master/LICENSE | +| resolve@1.1.7 | MIT | https://github.com/substack/node-resolve/raw/master/LICENSE | +| resolve@1.7.1 | MIT | https://github.com/browserify/resolve/raw/master/LICENSE | +| ret@0.1.15 | MIT | https://github.com/fent/ret.js/raw/master/LICENSE | +| retry@0.10.1 | MIT | https://github.com/tim-kos/node-retry/raw/master/License | +| right-align@0.1.3 | MIT | https://github.com/jonschlinkert/right-align/raw/master/LICENSE | +| rimraf@2.6.2 | ISC | https://github.com/isaacs/rimraf/raw/master/LICENSE | +| ripemd160@2.0.2 | MIT | https://github.com/crypto-browserify/ripemd160/raw/master/LICENSE | +| run-queue@1.0.3 | ISC | https://github.com/iarna/run-queue | +| rw@1.3.3 | BSD-3-Clause | http://github.com/mbostock/rw/raw/master/LICENSE | +| rxjs@6.2.0 | Apache-2.0 | https://github.com/ReactiveX/RxJS/raw/master/LICENSE.txt | +| safe-buffer@5.1.1 | MIT | https://github.com/feross/safe-buffer/raw/master/LICENSE | +| safe-buffer@5.1.2 | MIT | https://github.com/feross/safe-buffer/raw/master/LICENSE | +| safe-regex@1.1.0 | MIT | https://github.com/substack/safe-regex/raw/master/LICENSE | +| safer-buffer@2.1.2 | MIT | https://github.com/ChALkeR/safer-buffer/raw/master/LICENSE | +| sass-graph@2.2.4 | MIT | https://github.com/xzyfer/sass-graph | +| sass-loader@7.0.3 | MIT | https://github.com/webpack-contrib/sass-loader/raw/master/LICENSE | +| saucelabs@1.5.0 | MIT* | https://github.com/holidayextras/node-saucelabs/raw/master/README.md | +| sax@0.5.8 | BSD | https://github.com/isaacs/sax-js/raw/master/LICENSE | +| sax@0.6.1 | BSD | https://github.com/isaacs/sax-js/raw/master/LICENSE | +| sax@1.2.4 | ISC | https://github.com/isaacs/sax-js/raw/master/LICENSE | +| schema-utils@0.3.0 | MIT | https://github.com/webpack-contrib/schema-utils/raw/master/LICENSE | +| schema-utils@0.4.5 | MIT | https://github.com/webpack-contrib/schema-utils/raw/master/LICENSE | +| scss-tokenizer@0.2.3 | MIT | https://github.com/sasstools/scss-tokenizer/raw/master/LICENSE | +| select-hose@2.0.0 | MIT | https://github.com/indutny/select-hose | +| selenium-webdriver@2.53.3 | Apache-2.0 | https://github.com/SeleniumHQ/selenium/raw/master/LICENSE | +| selenium-webdriver@3.6.0 | Apache-2.0 | https://github.com/SeleniumHQ/selenium/raw/master/LICENSE | +| selfsigned@1.10.3 | MIT | https://github.com/jfromaniello/selfsigned | +| semver-dsl@1.0.1 | MIT | https://github.com/mgechev/semver-dsl | +| semver-intersect@1.3.1 | MIT | https://github.com/snyamathi/semver-intersect/raw/master/LICENSE | +| semver@4.3.6 | ISC | https://github.com/npm/node-semver/raw/master/LICENSE | +| semver@5.3.0 | ISC | https://github.com/npm/node-semver/raw/master/LICENSE | +| semver@5.5.0 | ISC | https://github.com/npm/node-semver/raw/master/LICENSE | +| send@0.16.2 | MIT | https://github.com/pillarjs/send/raw/master/LICENSE | +| serialize-javascript@1.5.0 | BSD-3-Clause | https://github.com/yahoo/serialize-javascript/raw/master/LICENSE | +| serve-index@1.9.1 | MIT | https://github.com/expressjs/serve-index/raw/master/LICENSE | +| serve-static@1.13.2 | MIT | https://github.com/expressjs/serve-static/raw/master/LICENSE | +| set-blocking@2.0.0 | ISC | https://github.com/yargs/set-blocking/raw/master/LICENSE.txt | +| set-immediate-shim@1.0.1 | MIT | https://github.com/sindresorhus/set-immediate-shim | +| set-value@0.4.3 | MIT | https://github.com/jonschlinkert/set-value/raw/master/LICENSE | +| set-value@2.0.0 | MIT | https://github.com/jonschlinkert/set-value/raw/master/LICENSE | +| setimmediate@1.0.5 | MIT | https://github.com/YuzuJS/setImmediate/raw/master/LICENSE.txt | +| setprototypeof@1.0.3 | ISC | https://github.com/wesleytodd/setprototypeof/raw/master/LICENSE | +| setprototypeof@1.1.0 | ISC | https://github.com/wesleytodd/setprototypeof/raw/master/LICENSE | +| sha.js@2.4.11 | (MIT AND BSD-3-Clause) | https://github.com/crypto-browserify/sha.js/raw/master/LICENSE | +| shallow-clone@1.0.0 | MIT | https://github.com/jonschlinkert/shallow-clone/raw/master/LICENSE | +| shebang-command@1.2.0 | MIT | https://github.com/kevva/shebang-command/raw/master/license | +| shebang-regex@1.0.0 | MIT | https://github.com/sindresorhus/shebang-regex/raw/master/license | +| signal-exit@3.0.2 | ISC | https://github.com/tapjs/signal-exit/raw/master/LICENSE.txt | +| silent-error@1.1.0 | ISC | https://github.com/stefanpenner/silent-error | +| slash@1.0.0 | MIT | https://github.com/sindresorhus/slash | +| slide@1.1.6 | ISC | https://github.com/isaacs/slide-flow-control/raw/master/LICENSE | +| snapdragon-node@2.1.1 | MIT | https://github.com/jonschlinkert/snapdragon-node/raw/master/LICENSE | +| snapdragon-util@3.0.1 | MIT | https://github.com/jonschlinkert/snapdragon-util/raw/master/LICENSE | +| snapdragon@0.8.2 | MIT | https://github.com/jonschlinkert/snapdragon/raw/master/LICENSE | +| sntp@1.0.9 | BSD | http://github.com/hueniverse/sntp/raw/master/LICENSE | +| socket.io-adapter@0.5.0 | MIT | https://github.com/Automattic/socket.io-adapter/raw/master/LICENSE | +| socket.io-client@1.7.3 | MIT | https://github.com/Automattic/socket.io-client/raw/master/LICENSE | +| socket.io-parser@2.3.1 | MIT | https://github.com/Automattic/socket.io-parser/raw/master/LICENSE | +| socket.io@1.7.3 | MIT | https://github.com/socketio/socket.io/raw/master/LICENSE | +| sockjs-client@1.1.4 | MIT | https://github.com/sockjs/sockjs-client/raw/master/COPYING | +| sockjs@0.3.19 | MIT | https://github.com/sockjs/sockjs-node/raw/master/COPYING | +| source-list-map@0.1.8 | MIT | https://github.com/webpack/source-list-map | +| source-list-map@2.0.0 | MIT | https://github.com/webpack/source-list-map | +| source-map-resolve@0.5.2 | MIT | https://github.com/lydell/source-map-resolve/raw/master/LICENSE | +| source-map-support@0.4.18 | MIT | https://github.com/evanw/node-source-map-support/raw/master/LICENSE.md | +| source-map-support@0.5.6 | MIT | https://github.com/evanw/node-source-map-support/raw/master/LICENSE.md | +| source-map-url@0.4.0 | MIT | https://github.com/lydell/source-map-url/raw/master/LICENSE | +| source-map@0.1.43 | BSD | http://opensource.org/licenses/BSD-3-Clause | +| source-map@0.2.0 | BSD | http://opensource.org/licenses/BSD-3-Clause | +| source-map@0.4.4 | BSD-3-Clause | http://github.com/mozilla/source-map | +| source-map@0.5.7 | BSD-3-Clause | http://github.com/mozilla/source-map/raw/master/LICENSE | +| source-map@0.6.1 | BSD-3-Clause | http://github.com/mozilla/source-map/raw/master/LICENSE | +| spdx-correct@3.0.0 | Apache-2.0 | https://github.com/jslicense/spdx-correct.js/raw/master/LICENSE | +| spdx-exceptions@2.1.0 | CC-BY-3.0 | https://github.com/kemitchell/spdx-exceptions.json | +| spdx-expression-parse@3.0.0 | MIT | https://github.com/jslicense/spdx-expression-parse.js/raw/master/LICENSE | +| spdx-license-ids@3.0.0 | CC0-1.0 | https://github.com/shinnn/spdx-license-ids | +| spdy-transport@2.1.0 | MIT | https://github.com/spdy-http2/spdy-transport | +| spdy@3.4.7 | MIT | https://github.com/indutny/node-spdy | +| split-string@3.1.0 | MIT | https://github.com/jonschlinkert/split-string/raw/master/LICENSE | +| sprintf-js@1.0.3 | BSD-3-Clause | https://github.com/alexei/sprintf.js/raw/master/LICENSE | +| sshpk@1.14.2 | MIT | https://github.com/arekinath/node-sshpk/raw/master/LICENSE | +| ssri@5.3.0 | ISC | https://github.com/zkat/ssri/raw/master/LICENSE.md | +| static-extend@0.1.2 | MIT | https://github.com/jonschlinkert/static-extend/raw/master/LICENSE | +| stats-webpack-plugin@0.6.2 | MIT | https://github.com/unindented/stats-webpack-plugin/raw/master/LICENSE | +| statuses@1.3.1 | MIT | https://github.com/jshttp/statuses/raw/master/LICENSE | +| statuses@1.4.0 | MIT | https://github.com/jshttp/statuses/raw/master/LICENSE | +| stdout-stream@1.4.0 | MIT* | https://github.com/mafintosh/stdout-stream/raw/master/LICENSE | +| stream-browserify@2.0.1 | MIT | https://github.com/substack/stream-browserify/raw/master/LICENSE | +| stream-each@1.2.2 | MIT | https://github.com/mafintosh/stream-each/raw/master/LICENSE | +| stream-http@2.8.3 | MIT | https://github.com/jhiesey/stream-http/raw/master/LICENSE | +| stream-shift@1.0.0 | MIT | https://github.com/mafintosh/stream-shift/raw/master/LICENSE | +| string_decoder@0.10.31 | MIT | https://github.com/rvagg/string_decoder/raw/master/LICENSE | +| string_decoder@1.1.1 | MIT | https://github.com/nodejs/string_decoder/raw/master/LICENSE | +| string-width@1.0.2 | MIT | https://github.com/sindresorhus/string-width/raw/master/license | +| string-width@2.1.1 | MIT | https://github.com/sindresorhus/string-width/raw/master/license | +| stringstream@0.0.6 | MIT | https://github.com/mhart/StringStream/raw/master/LICENSE.txt | +| strip-ansi@3.0.1 | MIT | https://github.com/chalk/strip-ansi/raw/master/license | +| strip-ansi@4.0.0 | MIT | https://github.com/chalk/strip-ansi/raw/master/license | +| strip-bom@2.0.0 | MIT | https://github.com/sindresorhus/strip-bom/raw/master/license | +| strip-bom@3.0.0 | MIT | https://github.com/sindresorhus/strip-bom/raw/master/license | +| strip-eof@1.0.0 | MIT | https://github.com/sindresorhus/strip-eof/raw/master/license | +| strip-indent@1.0.1 | MIT | https://github.com/sindresorhus/strip-indent/raw/master/license | +| strip-json-comments@2.0.1 | MIT | https://github.com/sindresorhus/strip-json-comments/raw/master/license | +| style-loader@0.21.0 | MIT | https://github.com/webpack-contrib/style-loader/raw/master/LICENSE | +| stylus-loader@3.0.2 | MIT | https://github.com/shama/stylus-loader/raw/master/LICENSE | +| stylus@0.54.5 | MIT | https://github.com/stylus/stylus/raw/master/LICENSE | +| supports-color@2.0.0 | MIT | https://github.com/chalk/supports-color/raw/master/license | +| supports-color@3.2.3 | MIT | https://github.com/chalk/supports-color/raw/master/license | +| supports-color@4.5.0 | MIT | https://github.com/chalk/supports-color/raw/master/license | +| supports-color@5.4.0 | MIT | https://github.com/chalk/supports-color/raw/master/license | +| symbol-observable@1.2.0 | MIT | https://github.com/blesh/symbol-observable/raw/master/license | +| tapable@1.0.0 | MIT | http://github.com/webpack/tapable | +| tar@2.2.1 | ISC | https://github.com/isaacs/node-tar/raw/master/LICENSE | +| tar@4.4.1 | ISC | https://github.com/npm/node-tar/raw/master/LICENSE | +| through@2.3.8 | MIT | https://github.com/dominictarr/through/raw/master/LICENSE.APACHE2 | +| through2@2.0.3 | MIT | https://github.com/rvagg/through2/raw/master/LICENSE.html | +| thunky@1.0.2 | MIT | https://github.com/mafintosh/thunky | +| timers-browserify@2.0.10 | MIT | https://github.com/jryans/timers-browserify/blob/master/LICENSE.md | +| tmp@0.0.24 | MIT | http://opensource.org/licenses/MIT | +| tmp@0.0.30 | MIT | https://github.com/raszi/node-tmp/raw/master/LICENSE | +| tmp@0.0.31 | MIT | https://github.com/raszi/node-tmp/raw/master/LICENSE | +| to-array@0.1.4 | MIT | http://github.com/Raynos/to-array/raw/master/LICENSE | +| to-arraybuffer@1.0.1 | MIT | https://github.com/jhiesey/to-arraybuffer/raw/master/LICENSE | +| to-fast-properties@1.0.3 | MIT | https://github.com/sindresorhus/to-fast-properties/raw/master/license | +| to-object-path@0.3.0 | MIT | https://github.com/jonschlinkert/to-object-path/raw/master/LICENSE | +| to-regex-range@2.1.1 | MIT | https://github.com/micromatch/to-regex-range/raw/master/LICENSE | +| to-regex@3.0.2 | MIT | https://github.com/jonschlinkert/to-regex/raw/master/LICENSE | +| toposort@1.0.7 | MIT | https://github.com/marcelklehr/toposort/raw/master/License | +| tough-cookie@2.3.4 | BSD-3-Clause | https://github.com/salesforce/tough-cookie/raw/master/LICENSE | +| tree-kill@1.2.0 | MIT | https://github.com/pkrumins/node-tree-kill | +| trim-newlines@1.0.0 | MIT | https://github.com/sindresorhus/trim-newlines/raw/master/license | +| trim-right@1.0.1 | MIT | https://github.com/sindresorhus/trim-right/raw/master/license | +| true-case-path@1.0.2 | Apache version 2.0 | https://github.com/barsh/true-case-path/raw/master/LICENSE | +| ts-node@5.0.1 | MIT | https://github.com/TypeStrong/ts-node/raw/master/LICENSE | +| tsickle@0.29.0 | MIT | https://github.com/angular/tsickle/raw/master/LICENSE | +| tslib@1.9.2 | Apache-2.0 | https://github.com/Microsoft/tslib/raw/master/LICENSE.txt | +| tslint@5.10.0 | Apache-2.0 | https://github.com/palantir/tslint/raw/master/LICENSE | +| tsutils@2.27.1 | MIT | https://github.com/ajafff/tsutils/raw/master/LICENSE | +| tty-browserify@0.0.0 | MIT | https://github.com/substack/tty-browserify/raw/master/LICENSE | +| tunnel-agent@0.4.3 | Apache-2.0 | https://github.com/mikeal/tunnel-agent/raw/master/LICENSE | +| tunnel-agent@0.6.0 | Apache-2.0 | https://github.com/mikeal/tunnel-agent/raw/master/LICENSE | +| tweetnacl@0.14.5 | Unlicense | https://github.com/dchest/tweetnacl-js/raw/master/LICENSE | +| type-check@0.3.2 | MIT | https://github.com/gkz/type-check/raw/master/LICENSE | +| type-is@1.6.16 | MIT | https://github.com/jshttp/type-is/raw/master/LICENSE | +| typedarray@0.0.6 | MIT | https://github.com/substack/typedarray/raw/master/LICENSE | +| typescript@2.7.2 | Apache-2.0 | https://github.com/Microsoft/TypeScript/raw/master/LICENSE.txt | +| typescript@2.9.1 | Apache-2.0 | https://github.com/Microsoft/TypeScript/raw/master/LICENSE.txt | +| uglify-es@3.3.9 | BSD-2-Clause | https://github.com/mishoo/UglifyJS2#harmony/raw/master/LICENSE | +| uglify-js@2.8.29 | BSD-2-Clause | https://github.com/mishoo/UglifyJS2/raw/master/LICENSE | +| uglify-js@3.3.28 | BSD-2-Clause | https://github.com/mishoo/UglifyJS2/raw/master/LICENSE | +| uglify-to-browserify@1.0.2 | MIT | https://github.com/ForbesLindesay/uglify-to-browserify/raw/master/LICENSE | + +# Go Packages +| Package | License | License URL | +|----------------------------------------------------|------------|-------------------------------------------------------------------------------| +| gopkg.in/yaml.v2 | Apache-2.0 | https://github.com/go-yaml/yaml/raw/v2/LICENSE | +| gopkg.in/square/go-jose.v2 | Apache-2.0 | https://github.com/square/go-jose/raw/master/LICENSE | +| gopkg.in/inf.v0 | | https://github.com/go-inf/inf/raw/master/LICENSE | +| gopkg.in/mgo.v2 | | https://github.com/go-mgo/mgo/raw/v2-unstable/LICENSE | +| google.golang.org/appengine | Apache-2.0 | https://github.com/golang/appengine/raw/master/LICENSE | +| k8s.io/client-go | Apache-2.0 | https://github.com/kubernetes/client-go/raw/master/LICENSE | +| k8s.io/api | Apache-2.0 | https://github.com/kubernetes/api/raw/master/LICENSE | +| k8s.io/apimachinery | Apache-2.0 | https://github.com/kubernetes/apimachinery/raw/master/LICENSE | +| golang.org/x/crypto | | https://github.com/golang/crypto/raw/master/LICENSE | +| golang.org/x/net | | https://github.com/golang/net/raw/master/LICENSE | +| golang.org/x/oauth2 | BSD-3 | https://github.com/golang/oauth2/raw/master/LICENSE | +| golang.org/x/time | | https://github.com/golang/time/raw/master/LICENSE | +| golang.org/x/sys | | https://github.com/golang/sys/raw/master/LICENSE | +| golang.org/x/text | | https://github.com/golang/text/raw/master/LICENSE | +| github.com/gorilla/mux | BSD-3 | https://github.com/gorilla/mux/raw/master/LICENSE | +| github.com/go-resty/resty | MIT | https://github.com/go-resty/resty/raw/master/LICENSE | +| github.com/mitchellh/mapstructure | MIT | https://github.com/mitchellh/mapstructure/raw/master/LICENSE | +| github.com/pelletier/go-toml | MIT | https://github.com/pelletier/go-toml/raw/master/LICENSE | +| github.com/olekukonko/tablewriter | MIT | https://github.com/olekukonko/tablewriter/raw/master/LICENSE.md | +| github.com/davecgh/go-spew | ISC | https://github.com/davecgh/go-spew/raw/master/LICENSE | +| github.com/pmezard/go-difflib | | https://github.com/pmezard/go-difflib/raw/master/LICENSE | +| github.com/caarlos0/env | MIT | https://github.com/caarlos0/env/raw/master/LICENSE.md | +| github.com/fsnotify/fsnotify | BSD-3 | https://github.com/fsnotify/fsnotify/raw/master/LICENSE | +| github.com/hashicorp/hcl | MPL-2 | https://github.com/hashicorp/hcl/raw/master/LICENSE | +| github.com/golang/glog | Apache-2.0 | https://github.com/golang/glog/raw/master/LICENSE | +| github.com/golang/protobuf | BSD-3 | https://github.com/golang/protobuf/raw/master/LICENSE | +| github.com/json-iterator/go | MIT | https://github.com/json-iterator/go/raw/master/LICENSE | +| github.com/stretchr/objx | MIT | https://github.com/stretchr/objx/raw/master/LICENSE | +| github.com/stretchr/testify | MIT | https://github.com/stretchr/testify/raw/master/LICENSE | +| github.com/google/gofuzz | Apache-2.0 | https://github.com/google/gofuzz/raw/master/LICENSE | +| github.com/olivere/elastic | MIT | https://github.com/olivere/elastic/raw/release-branch.v7/LICENSE | +| github.com/konsorten/go-windows-terminal-sequences | MIT | https://github.com/konsorten/go-windows-terminal-sequences/raw/master/LICENSE | +| github.com/pquerna/cachecontrol | Apache-2.0 | https://github.com/pquerna/cachecontrol/raw/master/LICENSE | +| github.com/briandowns/spinner | Apache-2.0 | https://github.com/briandowns/spinner/raw/master/LICENSE | +| github.com/magiconair/properties | | https://github.com/magiconair/properties/raw/master/LICENSE | +| github.com/fatih/color | MIT | https://github.com/fatih/color/raw/master/LICENSE.md | +| github.com/dgrijalva/jwt-go | MIT | https://github.com/dgrijalva/jwt-go/raw/master/LICENSE | +| github.com/sirupsen/logrus | MIT | https://github.com/sirupsen/logrus/raw/master/LICENSE | +| github.com/googleapis/gnostic | Apache-2.0 | https://github.com/googleapis/gnostic/raw/master/LICENSE | +| github.com/spf13/afero | Apache-2.0 | https://github.com/spf13/afero/raw/master/LICENSE.txt | +| github.com/spf13/cast | MIT | https://github.com/spf13/cast/raw/master/LICENSE | +| github.com/spf13/jwalterweatherman | MIT | https://github.com/spf13/jwalterweatherman/raw/master/LICENSE | +| github.com/spf13/viper | MIT | https://github.com/spf13/viper/raw/master/LICENSE | +| github.com/spf13/pflag | BSD-3 | https://github.com/spf13/pflag/raw/master/LICENSE | +| github.com/spf13/cobra | Apache-2.0 | https://github.com/spf13/cobra/raw/master/LICENSE.txt | +| github.com/modern-go/reflect2 | Apache-2.0 | https://github.com/modern-go/reflect2/raw/master/LICENSE | +| github.com/modern-go/concurrent | Apache-2.0 | https://github.com/modern-go/concurrent/raw/master/LICENSE | +| github.com/mailru/easyjson | MIT | https://github.com/mailru/easyjson/raw/master/LICENSE | +| github.com/coreos/go-oidc | Apache-2.0 | https://github.com/coreos/go-oidc/raw/v2/LICENSE | +| github.com/inconshreveable/mousetrap | | https://github.com/inconshreveable/mousetrap/raw/master/LICENSE | +| github.com/gogo/protobuf | | https://github.com/gogo/protobuf/raw/master/LICENSE | +| github.com/mattn/go-isatty | MIT | https://github.com/mattn/go-isatty/raw/master/LICENSE | +| github.com/mattn/go-runewidth | MIT | https://github.com/mattn/go-runewidth/raw/master/LICENSE | +| github.com/mattn/go-colorable | MIT | https://github.com/mattn/go-colorable/raw/master/LICENSE | +| github.com/pkg/errors | BSD-2 | https://github.com/pkg/errors/raw/master/LICENSE | +| github.com/ghodss/yaml | | https://github.com/ghodss/yaml/raw/master/LICENSE | diff --git a/appliancekit/README.md b/appliancekit/README.md new file mode 100644 index 00000000..bd98eded --- /dev/null +++ b/appliancekit/README.md @@ -0,0 +1,75 @@ +# Building the Pure1 Unplugged Appliance +The base for this is CentOS. We use a few tools to help. + +# TL;DR: + +Run +```bash +./scripts/build/build_installer_iso_in_docker.sh +``` + +This goes off and creates a special CentOS docker image (as needed) and then inside of it uses Lorax to construct a fresh +minimal image with only our stuff in it. Output from this script is in `/bin/iso`. The resulting ISO can be +booted from and used to install the Pure1 Unplugged appliance. + +# Lorax +We build the image using [Lorax](https://weldr.io/lorax/lorax.html). There is a docker image and some helpers +in [../images/lorax-build](../images/lorax-build). + +# lorax-builder image +Build it with the helper via + +```bash +./scripts/build/build_lorax_image.sh +``` + +This image has a copy of all the tooling required. + +_Note:_ To build appliance images (.iso, .qcow2, etc) you will need to run it as privileged! It doesn't seem to be +able to create loopback devices without it... + +# CentOS Base +The version of CentOS we are building is based 100% off the docker image version, more specifically the version it +is using with its yum repositories. Lorax will pull from the configured repos to grab the OS and kernel. See the +`lorax-build` image for details. To update just change the version specified. + +# Customizing CentOS +We need to pre-install some packages (docker, etc) and then drop our content into the image. This is done with a +combination of Lorax templates, RPM voodoo, kickstart files, and a little luck. + +From a high level there are a few steps involved... + +1) Download all the RPMs we will eventually need on our system into our tmp build dir (see [rpm-list.txt](./rpm-list.txt)). +2) Create a yum repo from the directory +3) Create an RPM containing the repo _and_ some config files we need, this ones called `pure1-unplugged-boot-config` +4) Create _another_ yum repo with only our RPM in it +5) Tell lorax via cli arg to use the repo from (4) as a "source" for the image +6) Lorax (while processing our template) will install our `pure1-unplugged-boot-config` RPM, which unpacks the big yum repo into the installtree +7) That same template will install our configs (kickstart files, etc) +8) Another lorax template (our `arch` template) then will copy the installed repository from the installtree to the special +`iso-graft` dir. This one gets grafted into the installer iso. + +At boot time the anaconda image is loaded and run, this linux live image is what was built from the templates in step 6/7. +It defaults to using our kickstart file which in turn points to the "cdrom" image we smuggled RPMs into (same way the "all-in-one" DVD's do). + +## Background Reading + +* [https://weldr.io/lorax/](https://weldr.io/lorax/) +* [https://weldr.io/lorax/lorax.html#custom-templates](https://weldr.io/lorax/lorax.html#custom-templates) +* [https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/sect-kickstart-syntax](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/installation_guide/sect-kickstart-syntax) + +# Upgrading RPM's +1. Install from the ISO as normal (including deployment and everything required to be up and running) +1. Add the external CentOS mirrors (break our offline-only rule), if needed snag the repo list from a normal CentOS version. +1. Add the kubernetes repo (see lorax image build for reference) +1. Ensure all the required packages are installed by doing something like `cat rpm-list.txt | xargs yum install -y` + * If there are errors it likely means we need to upgrade some system packages, fix them and don't ignore them! +1. Do a normal YUM update for the package *WARNING: DO NOT UPDATE `docker-ce` UNLESS REQUIRED! IT IS PINNED TO AN OLDER VERSION, SEE [https://kubernetes.io/docs/setup/cri/#docker](https://kubernetes.io/docs/setup/cri/#docker)* +1. Re-gen the `rpm-list.txt` file by running: + ```bash + rpm -qa | sort | awk '!a[$0]++' > rpm-list.txt + ``` + This gets all installed RPMs, sorts them by name, and then removes any duplicates +1. Save the new rpm-list.txt in the repo +_Note_: If any new repositories are required, ensure that they have been added to the `lorax-build` Docker image so +that the RPM's can be downloaded. diff --git a/appliancekit/anaconda/anaconda-gtk.css b/appliancekit/anaconda/anaconda-gtk.css new file mode 100644 index 00000000..64812c02 --- /dev/null +++ b/appliancekit/anaconda/anaconda-gtk.css @@ -0,0 +1,203 @@ +/* Anaconda gtk style overrides */ + +/* Define styles to apply to the GtkLevelBar widgets for different values. + * + * This stylesheet defines properties for "low", "medium" and "high" level bar + * levels. The level bars themselves need to define what style applies at what + * value using gtk_level_bar_add_offset_value. Gtk defines "low" and "high" by + * default, but it defines them for level bars using a continuous value between + * 0 and 1, so our discrete level bars are effectively always at the "high" + * level. + * + * Fun surprises that might change in future versions: + * + * - Defining properties for a level will set properties on both the filled + * portion and the empty portion of the level bar. So if all of the display + * properties are set, which we do, the level bar effectively becomes 100% + * filled with whatever properties are set. Copying the .empty-fill-block + * properties from the theme so that they apply at the application level + * works around this. + * + * - There's a bug in the handling of the maximum offset in that it only + * applies when value == max-value, rather than when it's between + * max-value and the next lower offset. For example, consider a + * discrete-mode level bar with a max-value of 4 and offsets defined as + * "low": 2.0, "medium": 3.0 and "high": 4.0. Value 1 will be low, + * value 2 will be medium, value 3 will be in an undefined no-man's land, + * and value 4 will be high. To get around this we re-define the default + * fill-block values as the same as fill-block.level-high. + * + * - The GNOME Adwaita theme applies a gradient to the progress bar when the + * window is focused. It does this by redefining the colors in a + * background-image property, so unless we reset background-image our colors + * will only apply when the window is out of focus, which uses the :backdrop + * selector. + */ + +@define-color anaconda_level_bar_low red; +@define-color anaconda_level_bar_medium orange; +@define-color anaconda_level_bar_high green; + +.level-bar.fill-block.level-low { + border-color: darker(@anaconda_level_bar_low); + background-color: @anaconda_level_bar_low; + background-image: none; +} + +.level-bar.fill-block.level-medium { + border-color: darker(@anaconda_level_bar_medium); + background-color: @anaconda_level_bar_medium; + background-image: none; +} + +.level-bar.fill-block, +.level-bar.fill-block.level-high { + border-color: darker(@anaconda_level_bar_high); + background-color: @anaconda_level_bar_high; + background-image: none; +} + +.level-bar.fill-block.empty-fill-block { + background-color: transparent; + background-image: none; + border-color: alpha(#000000, 0.1); +} + +/* As of gnome-themes-standard 3.9.90, the Adwaita theme uses the same color + * for all GtkInfoBars regardless of the MessageType. + * (https://bugzilla.gnome.org/show_bug.cgi?id=704266, commit 6bfa3aa0). The + * colors were actually kind of ok, and also the new colors are borderline + * unreadable, so these rules revert that change and set different colors. + */ + +@define-color info_fg_color black; +@define-color info_bg_color rgb (252, 252, 189); +@define-color warning_fg_color black; +@define-color warning_bg_color rgb (250, 173, 61); +@define-color question_fg_color white; +@define-color question_bg_color rgb (138, 173, 212); +@define-color error_fg_color white; +@define-color error_bg_color rgb (237, 54, 54); + +.info { + background-color: @info_bg_color; + color: @info_fg_color; + border-color: darker(@info_bg_color); +} + +.warning { + background-color: @warning_bg_color; + color: @warning_fg_color; + border-color: darker(@warning_bg_color); +} + +.question { + background-color: @question_bg_color; + color: @question_fg_color; + border-color: darker(@question_bg_color); +} + +.error { + background-color: @error_bg_color; + color: @error_fg_color; + border-color: darker(@error_bg_color); +} + +.info, +.warning, +.question, +.error { + text-shadow: none; +} + +/* vendor-specific colors/images */ + +@define-color redhat #021519; +@define-color fedora #006eb4; +@define-color pure-grey #ffffff; + +/* logo and sidebar classes for RHEL */ + +/* The sidebar consists of three parts: a background, a logo, and a product logo, + * rendered in that order. The product logo is empty by default and is intended + * to be overridden by a stylesheet in product.img. + */ +.logo-sidebar { + background-image: url('/usr/share/anaconda/pixmaps/sidebar-bg.png'); + background-color: @pure-grey; + background-repeat: no-repeat; +} + +/* Add a logo to the sidebar */ +.logo { + background-image: url('/usr/share/anaconda/pixmaps/sidebar-logo.png'); + background-position: 50% 20px; + background-repeat: no-repeat; + background-color: transparent; +} + +/* This is a placeholder to be filled by a product-specific logo. */ +.product-logo { + background-image: none; + background-color: transparent; +} + +AnacondaSpokeWindow #nav-box { + background-color: @pure-grey; + background-image: url('/usr/share/anaconda/pixmaps/topbar-bg.png'); + background-repeat: no-repeat; + color: white; +} + +AnacondaSpokeWindow #layout-indicator { + color: black; +} + +/* Remove the box-shadow from buttons in the nav-box because it adds a white stripe + * below the buttons and makes them look dumb */ +AnacondaSpokeWindow #nav-box GtkButton { + box-shadow: none; +} + +/* These rules were removed when the Adwaita theme moved from + * gnome-themes-standard to gtk. The selectors had been wildcards, but after + * the move they were replaced with more specific selectors, because gtk is + * maintained by garbage people who don't care about how anyone else's + * applications look. We need to apply the old style to anconda's custom + * widgets in order for the selection highlight and insensitive shading to + * appear. + */ +@define-color anaconda_selected_bg_color #4a90d9; +@define-color anaconda_selected_fg_color #ffffff; + +AnacondaMountpointSelector:selected, +AnacondaDiskOverview:selected, +AnacondaSpokeSelector:selected, +AnacondaMountpointSelector:selected:focus, +AnacondaDiskOverview:selected:focus, +AnacondaSpokeSelector:selected:focus { + background-color: @anaconda_selected_bg_color; + color: @anaconda_selected_fg_color; +} + +@define-color anaconda_insensitive_bg_color #f4f4f2; +@define-color anaconda_insensitive_fg_color #a7aba7; +@define-color anaconda_internal_element_color #888a85; +@define-color anaconda_insensitive_borders shade(@anaconda_internal_element_color, 1.37); + +AnacondaMountpointSelector:disabled, +AnacondaDiskOverview:disabled, +AnacondaSpokeSelector:disabled { + background-color: @anaconda_insensitive_bg_color; + color: @anaconda_insensitive_fg_color; + border-color: @anaconda_insensitive_borders; +} + +/* When multi-column GtkTreeViews set a row separator, the horizontal-separator + * style property is still applied to the row separator, breaking the row + * separator up for each column. It looks kind of dumb. Provide a way to not do + * that. + */ +treeview.solid-separator { + -GtkTreeView-horizontal-separator: 0; +} \ No newline at end of file diff --git a/appliancekit/anaconda/pixmaps/anaconda-selected-icon.svg b/appliancekit/anaconda/pixmaps/anaconda-selected-icon.svg new file mode 100644 index 00000000..e2faa038 --- /dev/null +++ b/appliancekit/anaconda/pixmaps/anaconda-selected-icon.svg @@ -0,0 +1,141 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + diff --git a/appliancekit/anaconda/pixmaps/dialog-warning-symbolic.svg b/appliancekit/anaconda/pixmaps/dialog-warning-symbolic.svg new file mode 100644 index 00000000..8349c5df --- /dev/null +++ b/appliancekit/anaconda/pixmaps/dialog-warning-symbolic.svg @@ -0,0 +1,30 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + diff --git a/appliancekit/anaconda/pixmaps/left-arrow-icon.png b/appliancekit/anaconda/pixmaps/left-arrow-icon.png new file mode 100644 index 00000000..fc25a91c Binary files /dev/null and b/appliancekit/anaconda/pixmaps/left-arrow-icon.png differ diff --git a/appliancekit/anaconda/pixmaps/right-arrow-icon.png b/appliancekit/anaconda/pixmaps/right-arrow-icon.png new file mode 100644 index 00000000..371f5035 Binary files /dev/null and b/appliancekit/anaconda/pixmaps/right-arrow-icon.png differ diff --git a/appliancekit/anaconda/pixmaps/rnotes/en/pure1-banner.png b/appliancekit/anaconda/pixmaps/rnotes/en/pure1-banner.png new file mode 100644 index 00000000..20c2234b Binary files /dev/null and b/appliancekit/anaconda/pixmaps/rnotes/en/pure1-banner.png differ diff --git a/appliancekit/anaconda/pixmaps/sidebar-bg.png b/appliancekit/anaconda/pixmaps/sidebar-bg.png new file mode 100644 index 00000000..9240aa3b Binary files /dev/null and b/appliancekit/anaconda/pixmaps/sidebar-bg.png differ diff --git a/appliancekit/anaconda/pixmaps/sidebar-logo.png b/appliancekit/anaconda/pixmaps/sidebar-logo.png new file mode 100644 index 00000000..b21bb364 Binary files /dev/null and b/appliancekit/anaconda/pixmaps/sidebar-logo.png differ diff --git a/appliancekit/anaconda/pixmaps/topbar-bg.png b/appliancekit/anaconda/pixmaps/topbar-bg.png new file mode 100644 index 00000000..d47e0f1f Binary files /dev/null and b/appliancekit/anaconda/pixmaps/topbar-bg.png differ diff --git a/appliancekit/anaconda/pure.ks b/appliancekit/anaconda/pure.ks new file mode 100644 index 00000000..b29c5199 --- /dev/null +++ b/appliancekit/anaconda/pure.ks @@ -0,0 +1,61 @@ +# This kickstart file should be used instead of the default anaconda interactive one + +# Installation files source, force the cdrom (from our ISO) +install +cdrom + +firstboot --enable +eula --agreed + +# Basic auth setup +auth --enableshadow --passalgo=sha512 + +# Everyone has a us keyboard? +#keyboard --vckeymap=us --xlayouts='us' + +# Setting up language to English +lang en-US.UTF-8 + +# Default to something.. +timezone America/Los_Angeles --nontp --utc + +# Setting up MBR +zerombr +bootloader --location=mbr --boot-drive=sda + +# Setting up Logical Volume Manager and autopartitioning +ignoredisk --only-use=sda +clearpart --all --drives=sda --initlabel +autopart --fstype=ext4 --nohome --type=lvm + +# Configure the bootloader, override the MBR +bootloader --location=mbr --boot-drive=sda + +# Setting up firewall and enabling SSH for remote management +firewall --enabled --service=ssh + +# Setup some starter services +services --enabled=sshd + +# Setting up Security-Enhanced Linux into permissive, as required by kubernetes +# https://kubernetes.io/docs/setup/independent/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl +selinux --permissive + +# Eject cdrom and reboot when we are done installing +reboot --eject + +# Installing only packages we need for pure1-unplugged, these need to all be available from cdrom +# The rpm-comps.xml defines the Pure1 Unplugged environment, specified below. +%packages +@^Pure1 Unplugged +%end + +%addon com_redhat_kdump --enable --reserve-mb='auto' +%end + +# Get rid of the standard yum repositories, ours get added in later +# but avoid any issues between OS install and pure1-unplugged setup +%post +!/bin/bash +rm /etc/yum.repos.d/*.repo +%end diff --git a/appliancekit/pure-lorax-arch.tmpl b/appliancekit/pure-lorax-arch.tmpl new file mode 100644 index 00000000..0069f7f6 --- /dev/null +++ b/appliancekit/pure-lorax-arch.tmpl @@ -0,0 +1,9 @@ +# This template runs when building the actual install ISO (after building the anaconda img) + +# Assume pure1-unplugged-boot-config has already been installed +# We have to use some magic to copy things to the right place since the workdir +# that the final x86 templates key off of is outside the installtree for some reason.. +log "Setting up ${workdir}/iso-graft" +runcmd mkdir ${workdir}/iso-graft +runcmd cp -r ${workdir}/installroot/Packages ${workdir}/iso-graft +runcmd cp -r ${workdir}/installroot/repodata ${workdir}/iso-graft diff --git a/appliancekit/pure-lorax.tmpl b/appliancekit/pure-lorax.tmpl new file mode 100644 index 00000000..3ca331d5 --- /dev/null +++ b/appliancekit/pure-lorax.tmpl @@ -0,0 +1,18 @@ +# This template is run after runtime-install.tmpl and before runtime-postinstall.tmpl +# Files installed/created here are part of the anaconda boot image (not the actual iso we install from!) + +log "Installing pure1-unplugged-boot-config" +installpkg pure1-unplugged-boot-config +run_pkg_transaction + +log "Overwriting interactive-defaults.ks" +install opt/pure1-unplugged/anaconda/pure.ks /usr/share/anaconda/interactive-defaults.ks + +log "Overwriting anaconda style resources" +remove /usr/share/anaconda/pixmaps/rnotes/en/ +mkdir /usr/share/anaconda/pixmaps/rnotes/en/ +install opt/pure1-unplugged/anaconda/pixmaps/rnotes/en/pure1-banner.png /usr/share/anaconda/pixmaps/rnotes/en/pure1-banner.png +install opt/pure1-unplugged/anaconda/pixmaps/sidebar-bg.png /usr/share/anaconda/pixmaps/sidebar-bg.png +install opt/pure1-unplugged/anaconda/pixmaps/sidebar-logo.png /usr/share/anaconda/pixmaps/sidebar-logo.png +install opt/pure1-unplugged/anaconda/pixmaps/topbar-bg.png /usr/share/anaconda/pixmaps/topbar-bg.png +install opt/pure1-unplugged/anaconda/anaconda-gtk.css /usr/share/anaconda/anaconda-gtk.css diff --git a/appliancekit/rpm-comps.xml b/appliancekit/rpm-comps.xml new file mode 100644 index 00000000..435936a2 --- /dev/null +++ b/appliancekit/rpm-comps.xml @@ -0,0 +1,170 @@ + + + + + core + Core + true + false + + audit + basesystem + bash + biosdevname + btrfs-progs + coreutils + cronie + curl + dhclient + e2fsprogs + filesystem + firewalld + glibc + hostname + initscripts + iproute + iprutils + iptables + iputils + irqbalance + jq + kbd + kexec-tools + less + man-db + nano + ncurses + openssh-clients + openssh-server + parted + passwd + plymouth + policycoreutils + procps-ng + rootfiles + rpm + rsyslog + screen + selinux-policy-targeted + setup + shadow-utils + sudo + systemd + tar + tmux + tuned + util-linux + vim-minimal + xfsprogs + yum + aic94xx-firmware + bfa-firmware + dracut-config-rescue + kernel-tools + libertas-sd8686-firmware + libertas-sd8787-firmware + libertas-usb8388-firmware + libsysfs + linux-firmware + microcode_ctl + NetworkManager + NetworkManager-team + NetworkManager-tui + NetworkManager-wifi + ql2100-firmware + ql2200-firmware + ql23xx-firmware + rdma + dracut-config-generic + dracut-fips + dracut-fips-aesni + dracut-network + openssh-keycat + selinux-policy-mls + tboot + yum-utils + + + + pure1-unplugged + Pure1 Unplugged + true + false + + docker-ce + kubelet + kubeadm + kubectl + pure1-unplugged + bash-completion + + + + vmware-guest-tools + VMWare Guest Tools + true + true + + open-vm-tools + + + + hyperv-guest-tools + HyperV Guest Tools + true + true + + hyperv-daemons + hyperv-daemons-license + hypervkvpd + hypervkvpd + hypervfcopyd + hypervvssd + + + + qemu-guest-tools + QEMU Guest Tools + true + true + + qemu-guest-agent + + + + cloud-init + Cloud Init + false + true + + cloud-init + + + + + VM Guest Tools + + vmware-guest-tools + hyperv-guest-tools + qemu-guest-tools + cloud-init + + + + + pure1-unplugged + Pure1 Unplugged + Pure1 Unplugged Required Packages + 10 + + core + pure1-unplugged + + + vmware-guest-tools + hyperv-guest-tools + qemu-guest-tools + cloud-init + + + diff --git a/appliancekit/rpm-list.txt b/appliancekit/rpm-list.txt new file mode 100644 index 00000000..9acaa5b5 --- /dev/null +++ b/appliancekit/rpm-list.txt @@ -0,0 +1,362 @@ +acl-2.2.51-14.el7.x86_64 +aic94xx-firmware-30-6.el7.noarch +ansible-2.4.2.0-2.el7.noarch +audit-2.8.4-4.el7.x86_64 +audit-libs-2.8.4-4.el7.x86_64 +audit-libs-python-2.8.4-4.el7.x86_64 +authconfig-6.2.8-30.el7.x86_64 +basesystem-10.0-7.el7.centos.noarch +bash-4.2.46-31.el7.x86_64 +bash-completion-2.1-6.el7.noarch +bind-libs-lite-9.9.4-73.el7_6.x86_64 +bind-license-9.9.4-73.el7_6.noarch +bind-utils-9.9.4-73.el7_6.x86_64 +binutils-2.27-34.base.el7.x86_64 +biosdevname-0.7.3-1.el7.x86_64 +btrfs-progs-4.9.1-1.el7.x86_64 +bzip2-libs-1.0.6-13.el7.x86_64 +ca-certificates-2018.2.22-70.0.el7_5.noarch +centos-logos-70.0.6-3.el7.centos.noarch +centos-release-7-6.1810.2.el7.centos.x86_64 +checkpolicy-2.5-8.el7.x86_64 +chkconfig-1.7.4-1.el7.x86_64 +chrony-3.2-2.el7.x86_64 +cloud-init-18.2-1.el7.centos.1.x86_64 +conntrack-tools-1.4.4-4.el7.x86_64 +container-selinux-2.74-1.el7.noarch +coreutils-8.22-23.el7.x86_64 +cpio-2.11-27.el7.x86_64 +cracklib-2.9.0-11.el7.x86_64 +cracklib-dicts-2.9.0-11.el7.x86_64 +cri-tools-1.12.0-0.x86_64 +cronie-1.4.11-20.el7_6.x86_64 +cronie-anacron-1.4.11-20.el7_6.x86_64 +crontabs-1.11-6.20121102git.el7.noarch +cryptsetup-libs-2.0.3-3.el7.x86_64 +curl-7.29.0-51.el7.x86_64 +cyrus-sasl-lib-2.1.26-23.el7.x86_64 +dbus-1.10.24-12.el7.x86_64 +dbus-glib-0.100-7.el7.x86_64 +dbus-libs-1.10.24-12.el7.x86_64 +dbus-python-1.1.1-9.el7.x86_64 +device-mapper-1.02.149-10.el7_6.3.x86_64 +device-mapper-event-1.02.149-10.el7_6.3.x86_64 +device-mapper-event-libs-1.02.149-10.el7_6.3.x86_64 +device-mapper-libs-1.02.149-10.el7_6.3.x86_64 +device-mapper-persistent-data-0.7.3-3.el7.x86_64 +dhclient-4.2.5-68.el7.centos.1.x86_64 +dhcp-common-4.2.5-68.el7.centos.1.x86_64 +dhcp-libs-4.2.5-68.el7.centos.1.x86_64 +diffutils-3.3-4.el7.x86_64 +dmidecode-3.1-2.el7.x86_64 +docker-ce-18.06.1.ce-3.el7.x86_64 +dracut-033-554.el7.x86_64 +dracut-config-rescue-033-554.el7.x86_64 +dracut-network-033-554.el7.x86_64 +e2fsprogs-1.42.9-13.el7.x86_64 +e2fsprogs-libs-1.42.9-13.el7.x86_64 +ebtables-2.0.10-16.el7.x86_64 +elfutils-default-yama-scope-0.172-2.el7.noarch +elfutils-libelf-0.172-2.el7.x86_64 +elfutils-libs-0.172-2.el7.x86_64 +emacs-24.3-22.el7.x86_64 +epel-release-7-11.noarch +ethtool-4.8-9.el7.x86_64 +expat-2.1.0-10.el7_3.x86_64 +file-5.11-35.el7.x86_64 +file-libs-5.11-35.el7.x86_64 +filesystem-3.2-25.el7.x86_64 +findutils-4.5.11-6.el7.x86_64 +fipscheck-1.4.1-6.el7.x86_64 +fipscheck-lib-1.4.1-6.el7.x86_64 +firewalld-0.5.3-5.el7.noarch +firewalld-filesystem-0.5.3-5.el7.noarch +freetype-2.8-12.el7_6.1.x86_64 +fuse-2.9.2-11.el7.x86_64 +fuse-libs-2.9.2-11.el7.x86_64 +gawk-4.0.2-4.el7_3.1.x86_64 +gdbm-1.10-8.el7.x86_64 +GeoIP-1.5.0-13.el7.x86_64 +gettext-0.19.8.1-2.el7.x86_64 +gettext-libs-0.19.8.1-2.el7.x86_64 +glib2-2.56.1-2.el7.x86_64 +glibc-2.17-260.el7_6.3.x86_64 +glibc-common-2.17-260.el7_6.3.x86_64 +gmp-6.0.0-15.el7.x86_64 +gnupg2-2.0.22-5.el7_5.x86_64 +gobject-introspection-1.56.1-1.el7.x86_64 +gpgme-1.3.2-5.el7.x86_64 +gpg-pubkey-f4a80eb5-53a7ff4b +grep-2.20-3.el7.x86_64 +groff-base-1.22.2-8.el7.x86_64 +grub2-2.02-0.76.el7.centos.1.x86_64 +grub2-common-2.02-0.76.el7.centos.1.noarch +grub2-pc-2.02-0.76.el7.centos.1.x86_64 +grub2-pc-modules-2.02-0.76.el7.centos.1.noarch +grub2-tools-2.02-0.76.el7.centos.1.x86_64 +grub2-tools-extra-2.02-0.76.el7.centos.1.x86_64 +grub2-tools-minimal-2.02-0.76.el7.centos.1.x86_64 +grubby-8.28-25.el7.x86_64 +gzip-1.5-10.el7.x86_64 +hardlink-1.0-19.el7.x86_64 +hostname-3.13-3.el7.x86_64 +hwdata-0.252-9.1.el7.x86_64 +hyperv-daemons-0-0.34.20180415git.el7.x86_64 +hyperv-daemons-license-0-0.34.20180415git.el7.noarch +hypervfcopyd-0-0.34.20180415git.el7.x86_64 +hypervkvpd-0-0.34.20180415git.el7.x86_64 +hypervvssd-0-0.34.20180415git.el7.x86_64 +info-5.1-5.el7.x86_64 +initscripts-9.49.46-1.el7.x86_64 +iproute-4.11.0-14.el7.x86_64 +iprutils-2.4.16.1-1.el7.x86_64 +ipset-6.38-3.el7_6.x86_64 +ipset-libs-6.38-3.el7_6.x86_64 +iptables-1.4.21-28.el7.x86_64 +iputils-20160308-10.el7.x86_64 +irqbalance-1.0.7-11.el7.x86_64 +jansson-2.10-1.el7.x86_64 +json-c-0.11-4.el7_0.x86_64 +jq-1.5.1.el7.x86_64 +kbd-1.15.5-15.el7.x86_64 +kbd-legacy-1.15.5-15.el7.noarch +kbd-misc-1.15.5-15.el7.noarch +kernel-3.10.0-957.5.1.el7.x86_64 +kernel-tools-3.10.0-957.5.1.el7.x86_64 +kernel-tools-libs-3.10.0-957.5.1.el7.x86_64 +kexec-tools-2.0.15-21.el7.x86_64 +keyutils-libs-1.5.8-3.el7.x86_64 +kmod-20-23.el7.x86_64 +kmod-libs-20-23.el7.x86_64 +kpartx-0.4.9-123.el7.x86_64 +krb5-libs-1.15.1-37.el7_6.x86_64 +kubeadm-1.13.4-0.x86_64 +kubectl-1.13.4-0.x86_64 +kubelet-1.13.4-0.x86_64 +kubernetes-cni-0.6.0-0.x86_64 +less-458-9.el7.x86_64 +libacl-2.2.51-14.el7.x86_64 +libaio-0.3.109-13.el7.x86_64 +libassuan-2.1.0-3.el7.x86_64 +libattr-2.4.46-13.el7.x86_64 +libblkid-2.23.2-59.el7.x86_64 +libcap-2.22-9.el7.x86_64 +libcap-ng-0.7.5-4.el7.x86_64 +libcgroup-0.41-20.el7.x86_64 +libcom_err-1.42.9-13.el7.x86_64 +libcroco-0.6.12-4.el7.x86_64 +libcurl-7.29.0-51.el7.x86_64 +libdaemon-0.14-7.el7.x86_64 +libdb-5.3.21-24.el7.x86_64 +libdb-utils-5.3.21-24.el7.x86_64 +libdnet-1.12-13.1.el7.x86_64 +libdrm-2.4.91-3.el7.x86_64 +libedit-3.0-12.20121213cvs.el7.x86_64 +libestr-0.1.9-2.el7.x86_64 +libevent-2.0.21-4.el7.x86_64 +libfastjson-0.99.4-3.el7.x86_64 +libffi-3.0.13-18.el7.x86_64 +libgcc-4.8.5-36.el7.x86_64 +libgcrypt-1.5.3-14.el7.x86_64 +libgomp-4.8.5-36.el7.x86_64 +libgpg-error-1.12-3.el7.x86_64 +libicu-50.1.2-17.el7.x86_64 +libidn-1.28-4.el7.x86_64 +libmnl-1.0.3-7.el7.x86_64 +libmount-2.23.2-59.el7.x86_64 +libmspack-0.5-0.6.alpha.el7.x86_64 +libndp-1.2-7.el7.x86_64 +libnetfilter_conntrack-1.0.6-1.el7_3.x86_64 +libnetfilter_cthelper-1.0.0-9.el7.x86_64 +libnetfilter_cttimeout-1.0.0-6.el7.x86_64 +libnetfilter_queue-1.0.2-2.el7_2.x86_64 +libnfnetlink-1.0.1-4.el7.x86_64 +libnl3-3.2.28-4.el7.x86_64 +libnl3-cli-3.2.28-4.el7.x86_64 +libpciaccess-0.14-1.el7.x86_64 +libpipeline-1.2.3-3.el7.x86_64 +libpng-1.5.13-7.el7_2.x86_64 +libpwquality-1.2.3-5.el7.x86_64 +libseccomp-2.3.1-3.el7.x86_64 +libselinux-2.5-14.1.el7.x86_64 +libselinux-python-2.5-14.1.el7.x86_64 +libselinux-utils-2.5-14.1.el7.x86_64 +libsemanage-2.5-14.el7.x86_64 +libsemanage-python-2.5-14.el7.x86_64 +libsepol-2.5-10.el7.x86_64 +libsmartcols-2.23.2-59.el7.x86_64 +libss-1.42.9-13.el7.x86_64 +libssh2-1.4.3-12.el7.x86_64 +libstdc++-4.8.5-36.el7.x86_64 +libsysfs-2.1.0-16.el7.x86_64 +libtasn1-4.10-1.el7.x86_64 +libteam-1.27-5.el7.x86_64 +libtool-ltdl-2.4.2-22.el7_3.x86_64 +libunistring-0.9.3-9.el7.x86_64 +libuser-0.60-9.el7.x86_64 +libutempter-1.1.6-4.el7.x86_64 +libuuid-2.23.2-59.el7.x86_64 +libverto-0.2.5-4.el7.x86_64 +libxml2-2.9.1-6.el7_2.3.x86_64 +libxml2-python-2.9.1-6.el7_2.3.x86_64 +libxslt-1.1.28-5.el7.x86_64 +libyaml-0.1.4-11.el7_0.x86_64 +linux-firmware-20180911-69.git85c5d90.el7.noarch +logrotate-3.8.6-17.el7.x86_64 +lsscsi-0.27-6.el7.x86_64 +lua-5.1.4-15.el7.x86_64 +lvm2-2.02.180-10.el7_6.3.x86_64 +lvm2-libs-2.02.180-10.el7_6.3.x86_64 +lz4-1.7.5-2.el7.x86_64 +lzo-2.06-8.el7.x86_64 +make-3.82-23.el7.x86_64 +man-db-2.6.3-11.el7.x86_64 +microcode_ctl-2.1-47.el7.x86_64 +mozjs17-17.0.0-20.el7.x86_64 +nano-2.3.1-10.el7.x86_64 +ncurses-5.9-14.20130511.el7_4.x86_64 +ncurses-base-5.9-14.20130511.el7_4.noarch +ncurses-libs-5.9-14.20130511.el7_4.x86_64 +net-tools-2.0-0.24.20131004git.el7.x86_64 +NetworkManager-1.12.0-8.el7_6.x86_64 +NetworkManager-libnm-1.12.0-8.el7_6.x86_64 +NetworkManager-team-1.12.0-8.el7_6.x86_64 +NetworkManager-tui-1.12.0-8.el7_6.x86_64 +NetworkManager-wifi-1.12.0-8.el7_6.x86_64 +newt-0.52.15-4.el7.x86_64 +newt-python-0.52.15-4.el7.x86_64 +nspr-4.19.0-1.el7_5.x86_64 +nss-3.36.0-7.1.el7_6.x86_64 +nss-pem-1.0.3-5.el7.x86_64 +nss-softokn-3.36.0-5.el7_5.x86_64 +nss-softokn-freebl-3.36.0-5.el7_5.x86_64 +nss-sysinit-3.36.0-7.1.el7_6.x86_64 +nss-tools-3.36.0-7.1.el7_6.x86_64 +nss-util-3.36.0-1.1.el7_6.x86_64 +numactl-libs-2.0.9-7.el7.x86_64 +oniguruma-5.9.5-3.el7.x86_64 +openldap-2.4.44-21.el7_6.x86_64 +openssh-7.4p1-16.el7.x86_64 +openssh-clients-7.4p1-16.el7.x86_64 +openssh-server-7.4p1-16.el7.x86_64 +openssl-1.0.2k-16.el7.x86_64 +openssl-libs-1.0.2k-16.el7.x86_64 +open-vm-tools-10.2.5-3.el7.x86_64 +os-prober-1.58-9.el7.x86_64 +p11-kit-0.23.5-3.el7.x86_64 +p11-kit-trust-0.23.5-3.el7.x86_64 +pam-1.1.8-22.el7.x86_64 +parted-3.1-29.el7.x86_64 +passwd-0.79-4.el7.x86_64 +pciutils-3.5.1-3.el7.x86_64 +pciutils-libs-3.5.1-3.el7.x86_64 +pcre-8.32-17.el7.x86_64 +pinentry-0.8.1-17.el7.x86_64 +pkgconfig-0.27.1-4.el7.x86_64 +plymouth-0.8.9-0.31.20140113.el7.centos.x86_64 +plymouth-core-libs-0.8.9-0.31.20140113.el7.centos.x86_64 +plymouth-scripts-0.8.9-0.31.20140113.el7.centos.x86_64 +policycoreutils-2.5-29.el7_6.1.x86_64 +policycoreutils-python-2.5-29.el7_6.1.x86_64 +polkit-0.112-18.el7_6.1.x86_64 +polkit-pkla-compat-0.1-4.el7.x86_64 +popt-1.13-16.el7.x86_64 +procps-ng-3.3.10-23.el7.x86_64 +pth-2.0.7-23.el7.x86_64 +pygpgme-0.3-9.el7.x86_64 +pyliblzma-0.5.3-11.el7.x86_64 +pyserial-2.6-6.el7.noarch +python-2.7.5-76.el7.x86_64 +python2-cryptography-1.7.2-2.el7.x86_64 +python2-jmespath-0.9.0-3.el7.noarch +python2-pyasn1-0.1.9-7.el7.noarch +python-babel-0.9.6-8.el7.noarch +python-backports-1.0-8.el7.x86_64 +python-backports-ssl_match_hostname-3.5.0.1-1.el7.noarch +python-cffi-1.6.0-5.el7.x86_64 +python-chardet-2.2.1-1.el7_1.noarch +python-configobj-4.7.2-7.el7.noarch +python-decorator-3.4.0-3.el7.noarch +python-enum34-1.0.4-1.el7.noarch +python-firewall-0.5.3-5.el7.noarch +python-gobject-base-3.22.0-1.el7_4.1.x86_64 +python-httplib2-0.9.2-1.el7.noarch +python-idna-2.4-1.el7.noarch +python-iniparse-0.4-9.el7.noarch +python-ipaddress-1.0.16-2.el7.noarch +python-IPy-0.75-6.el7.noarch +python-jinja2-2.7.2-2.el7.noarch +python-jsonpatch-1.2-4.el7.noarch +python-jsonpointer-1.9-2.el7.noarch +python-kitchen-1.1.1-5.el7.noarch +python-libs-2.7.5-76.el7.x86_64 +python-linux-procfs-0.4.9-4.el7.noarch +python-markupsafe-0.11-10.el7.x86_64 +python-paramiko-2.1.1-9.el7.noarch +python-passlib-1.6.5-2.el7.noarch +python-perf-3.10.0-957.5.1.el7.x86_64 +python-ply-3.4-11.el7.noarch +python-prettytable-0.7.2-3.el7.noarch +python-pycparser-2.14-1.el7.noarch +python-pycurl-7.19.0-19.el7.x86_64 +python-pyudev-0.15-9.el7.noarch +python-requests-2.6.0-1.el7_1.noarch +python-schedutils-0.4-6.el7.x86_64 +python-setuptools-0.9.8-7.el7.noarch +python-six-1.9.0-2.el7.noarch +python-slip-0.4.0-4.el7.noarch +python-slip-dbus-0.4.0-4.el7.noarch +python-urlgrabber-3.10-9.el7.noarch +python-urllib3-1.10.2-5.el7.noarch +pyxattr-0.5.1-5.el7.x86_64 +PyYAML-3.10-11.el7.x86_64 +qemu-guest-agent-2.12.0-2.el7.x86_64 +qrencode-libs-3.4.1-3.el7.x86_64 +readline-6.2-10.el7.x86_64 +rootfiles-8.1-11.el7.noarch +rpm-4.11.3-35.el7.x86_64 +rpm-build-libs-4.11.3-35.el7.x86_64 +rpm-libs-4.11.3-35.el7.x86_64 +rpm-python-4.11.3-35.el7.x86_64 +rsyslog-8.24.0-34.el7.x86_64 +screen-4.1.0-0.25.20120314git3c2946.el7.x86_64 +sed-4.2.2-5.el7.x86_64 +selinux-policy-3.13.1-229.el7_6.9.noarch +selinux-policy-targeted-3.13.1-229.el7_6.9.noarch +setools-libs-3.3.8-4.el7.x86_64 +setup-2.8.71-10.el7.noarch +shadow-utils-4.1.5.1-25.el7.x86_64 +shared-mime-info-1.8-4.el7.x86_64 +slang-2.2.4-11.el7.x86_64 +snappy-1.1.0-3.el7.x86_64 +socat-1.7.3.2-2.el7.x86_64 +sqlite-3.7.17-8.el7.x86_64 +sshpass-1.06-2.el7.x86_64 +sudo-1.8.23-3.el7.x86_64 +systemd-219-62.el7_6.5.x86_64 +systemd-libs-219-62.el7_6.5.x86_64 +systemd-sysv-219-62.el7_6.5.x86_64 +sysvinit-tools-2.88-14.dsf.el7.x86_64 +tar-1.26-35.el7.x86_64 +tcp_wrappers-libs-7.6-77.el7.x86_64 +teamd-1.27-5.el7.x86_64 +tmux-1.8-4.el7.x86_64 +tuned-2.10.0-6.el7.noarch +tzdata-2018i-1.el7.noarch +ustr-1.0.4-16.el7.x86_64 +util-linux-2.23.2-59.el7.x86_64 +vim-enhanced-7.4.160-5.el7.x86_64 +vim-minimal-7.4.160-5.el7.x86_64 +virt-what-1.18-4.el7.x86_64 +which-2.20-7.el7.x86_64 +wpa_supplicant-2.6-12.el7.x86_64 +xfsprogs-4.5.0-18.el7.x86_64 +xmlsec1-1.2.20-7.el7_4.x86_64 +xmlsec1-openssl-1.2.20-7.el7_4.x86_64 +xz-5.2.2-1.el7.x86_64 +xz-libs-5.2.2-1.el7.x86_64 +yum-3.4.3-161.el7.centos.noarch +yum-metadata-parser-1.1.4-10.el7.x86_64 +yum-plugin-fastestmirror-1.1.31-50.el7.noarch +yum-utils-1.1.31-50.el7.noarch +zlib-1.2.7-18.el7.x86_64 \ No newline at end of file diff --git a/cmd/api-server/main.go b/cmd/api-server/main.go new file mode 100644 index 00000000..abe63950 --- /dev/null +++ b/cmd/api-server/main.go @@ -0,0 +1,83 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "fmt" + "net/http" + "os" + "time" + + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/apis/server" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/elastic" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/hooks" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/version" + log "github.com/sirupsen/logrus" +) + +const ( + port = 8080 + sourceName = "api-server" +) + +func main() { + log.SetLevel(log.TraceLevel) + log.SetReportCaller(true) + + err := server.ParseAPIServerEnvironmentVariables() + if err != nil { + log.WithError(err).Fatal("Error loading server environment variables, exiting...") + os.Exit(1) + return + } + + databaseService, err := elastic.InitializeClient(server.APIServerEnv.ElasticHost, 0, time.Second*5) + if err != nil { + log.WithError(err).Fatal("Error initializing elastic client, exiting...") + os.Exit(1) + return + } + + err = databaseService.CreateArrayTemplate(context.Background()) + if err != nil { + log.WithError(err).Fatal("Error initializing array template") + os.Exit(1) + return + } + + errorHook, err := hooks.NewErrorLogHook(sourceName, []log.Level{log.WarnLevel, log.ErrorLevel, log.FatalLevel}, databaseService) + if err != nil { + log.WithError(err).Fatal("Error creating ErrorLogHook, exiting...") + os.Exit(1) + return + } + + log.AddHook(errorHook) + + router := server.NewRouter() + log.WithFields(log.Fields{ + "version": version.Get(), + "port": port, + }).Debug("Starting API server") + + err = http.ListenAndServe(fmt.Sprintf(":%d", port), router) + if err != nil { + log.WithFields(log.Fields{ + "error": err, + "port": port, + }).Errorf("Failed to listen and serve") + } +} diff --git a/cmd/auth-server/main.go b/cmd/auth-server/main.go new file mode 100755 index 00000000..9d27d111 --- /dev/null +++ b/cmd/auth-server/main.go @@ -0,0 +1,77 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "crypto/rand" + "encoding/base64" + "fmt" + "os" + "time" + + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/auth/server" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/auth/server/tokenstore" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/elastic" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/hooks" + log "github.com/sirupsen/logrus" +) + +const ( + sourceName = "auth-server" +) + +func main() { + log.SetLevel(log.TraceLevel) + log.SetReportCaller(true) + + err := server.ParseAuthEnv() + if err != nil { + log.WithError(err).Fatal("Error loading auth server environment variables, exiting...") + os.Exit(1) + return + } + + databaseService, err := elastic.InitializeClient(server.AuthServerEnvConf.ElasticHost, 0, time.Second*5) + if err != nil { + log.WithError(err).Fatal("Error initializing elastic client, exiting...") + os.Exit(1) + return + } + + errorHook, err := hooks.NewErrorLogHook(sourceName, []log.Level{log.WarnLevel, log.ErrorLevel, log.FatalLevel}, databaseService) + if err != nil { + log.WithError(err).Fatal("Error creating ErrorLogHook, exiting...") + os.Exit(1) + return + } + + log.AddHook(errorHook) + + // Generate HMAC secret + bytes := make([]byte, 32) + _, err = rand.Read(bytes) + + if err != nil { + panic(fmt.Sprintf("Error generating HMAC secret: %v", err)) + } + tokenstore.HmacSecret = base64.URLEncoding.EncodeToString(bytes) + + err = server.Cmd().Execute() + if err != nil { + log.WithFields(log.Fields{ + "error": err, + }).Errorf("Failed to execute commands of Auth Server!") + } +} diff --git a/cmd/metrics-client/env.go b/cmd/metrics-client/env.go new file mode 100644 index 00000000..ed71b88f --- /dev/null +++ b/cmd/metrics-client/env.go @@ -0,0 +1,58 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "github.com/caarlos0/env" + log "github.com/sirupsen/logrus" +) + +var ( + metricsClientEnvConf *EnvMetricsClientConfig +) + +// EnvMetricsClientConfig represents a configuration object for managing Elastic and +// Metrics that is populated from system environment variables. +type EnvMetricsClientConfig struct { + NameSpace string `env:"METRICS_CLIENT_NAME_SPACE" envDefault:"pure1-unplugged"` + MetricsIndexPrefix string `env:"ELASTIC_METRICS_INDEX_PREFIX" envDefault:"pure1-unplugged-metrics"` + MetricsTypeName string `env:"ELASTIC_METRICS_TYPE_NAME" envDefault:"metrics"` + VolumeMetricsIndexPrefix string `env:"ELASTIC_VOLUME_METRICS_INDEX_PREFIX" envDefault:"pure1-unplugged-volumes"` + VolumeMetricsTypeName string `env:"ELASTIC_VOLUME_METRICS_TYPE_NAME" envDefault:"metrics"` + MetricsRetentionCheckPeriod int `env:"ELASTIC_METRICS_RETENTION_CHECK_PERIOD" envDefault:"24"` + MetricsRetentionPeriod int `env:"ELASTIC_METRICS_RETENTION_PERIOD" envDefault:"31"` + AlertsRetentionPeriod int `env:"ELASTIC_ALERTS_RETENTION_PERIOD" envDefault:"365"` + ErrorLogRetentionPeriod int `env:"ELASTIC_ERROR_LOG_RETENTION_PERIOD" envDefault:"1"` + StageTimerRetentionPeriod int `env:"ELASTIC_STAGE_TIMER_RETENTION_PERIOD" envDefault:"1"` + AlertsIndexName string `env:"ELASTIC_ALERT_INDEX_NAME" envDefault:"pure1-unplugged-alerts"` + AlertsTypeName string `env:"ELASTIC_ALERT_TYPE_NAME" envDefault:"alerts"` + Host string `env:"ELASTIC_HOST" envDefault:"localhost:9200"` + ArrayMetricCollectionPeriod int `env:"ELASTIC_ARRAY_METRIC_COLLECTION_PERIOD" envDefault:"30"` + FAVolumeMetricCollectionPeriod int `env:"ELASTIC_FA_VOLUME_METRIC_COLLECTION_PERIOD" envDefault:"30"` + FBVolumeMetricCollectionPeriod int `env:"ELASTIC_FB_VOLUME_METRIC_COLLECTION_PERIOD" envDefault:"300"` // Cannot collect as frequently as FA + WorkerPoolThreads int `env:"WORKER_THREADS" envDefault:"50"` // Reasonable defaults for most workloads + WorkerPoolBufferLength int `env:"WORKER_BUFFER_LENGTH" envDefault:"200"` +} + +func parseMetricsEnvironmentVariables() error { + log.WithField("config", metricsClientEnvConf).Debug("Initializing metrics client environment variables") + metricsClientEnvConf = new(EnvMetricsClientConfig) + err := env.Parse(metricsClientEnvConf) + if err != nil { + return err + } + log.WithField("config", metricsClientEnvConf).Debug("Done initializing metrics client environment variables") + return nil +} diff --git a/cmd/metrics-client/main.go b/cmd/metrics-client/main.go new file mode 100644 index 00000000..b20707c5 --- /dev/null +++ b/cmd/metrics-client/main.go @@ -0,0 +1,199 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "context" + "os" + "time" + + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/apiserver" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/array" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/elastic" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/hooks" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/jobs" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/resources" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/resources/metrics" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/workerpool" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/logger" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/version" + + log "github.com/sirupsen/logrus" +) + +const ( + sourceName = "metrics-client" +) + +func main() { + log.SetLevel(log.TraceLevel) + log.SetReportCaller(true) + // Censor API tokens from the output + log.SetFormatter(logger.CensorAPITokensFromFormatter(&log.TextFormatter{})) + log.WithFields(log.Fields{ + "version": version.Get(), + }).Info("Staring Metrics client") + + err := parseMetricsEnvironmentVariables() + if err != nil { + log.WithError(err).Fatal("Error parsing metrics client environment variables, exiting...") + os.Exit(1) + return + } + + discoveryService := apiserver.NewConnection("http://pure1-unplugged-api-server") + collectorFactory := array.NewRESTFactory(discoveryService) + databaseService, err := elastic.InitializeClient(metricsClientEnvConf.Host, 0, time.Second*5) + if err != nil { + log.WithError(err).Fatal("Error initializing elastic connection, exiting...") + os.Exit(1) + return + } + + ctx := context.Background() + + err = databaseService.CreateArrayMetricsTemplate(ctx) + if err != nil { + log.WithError(err).Fatal("Error initializing array metrics template") + os.Exit(1) + return + } + + err = databaseService.CreateVolumeMetricsTemplate(ctx) + if err != nil { + log.WithError(err).Fatal("Error initializing volume metrics template") + os.Exit(1) + return + } + + err = databaseService.CreateAlertsTemplate(ctx) + if err != nil { + log.WithError(err).Fatal("Error initializing alerts template") + os.Exit(1) + return + } + + timerHook, err := hooks.NewStageTimerHook(sourceName, databaseService) + if err != nil { + log.WithError(err).Fatal("Error creating StageTimerHook, exiting...") + os.Exit(1) + return + } + errorHook, err := hooks.NewErrorLogHook(sourceName, []log.Level{log.WarnLevel, log.ErrorLevel, log.FatalLevel}, databaseService) + if err != nil { + log.WithError(err).Fatal("Error creating ErrorLogHook, exiting...") + os.Exit(1) + return + } + log.AddHook(timerHook) + log.AddHook(errorHook) + + arrayMetricsCollectionFrequency := time.Duration(metricsClientEnvConf.ArrayMetricCollectionPeriod) * time.Second + faVolumeMetricsCollectionFrequency := time.Duration(metricsClientEnvConf.FAVolumeMetricCollectionPeriod) * time.Second + fbVolumeMetricsCollectionFrequency := time.Duration(metricsClientEnvConf.FBVolumeMetricCollectionPeriod) * time.Second + + arrayMetricsCollectionTicker := time.NewTicker(arrayMetricsCollectionFrequency) + faVolumeMetricsCollectionTicker := time.NewTicker(faVolumeMetricsCollectionFrequency) + fbVolumeMetricsCollectionTicker := time.NewTicker(fbVolumeMetricsCollectionFrequency) + dataRetentionTicker := time.NewTicker(time.Duration(metricsClientEnvConf.MetricsRetentionCheckPeriod) * time.Hour) + + workerPool := workerpool.CreateThreadPool(metricsClientEnvConf.WorkerPoolThreads, metricsClientEnvConf.WorkerPoolBufferLength) + + for { + select { + case <-arrayMetricsCollectionTicker.C: + createArrayMetricsJobs(&workerPool, discoveryService, databaseService, collectorFactory, arrayMetricsCollectionFrequency) + break + case <-faVolumeMetricsCollectionTicker.C: + createVolumeMetricsJobs(&workerPool, discoveryService, databaseService, collectorFactory, faVolumeMetricsCollectionFrequency, common.FlashArray) + break + case <-fbVolumeMetricsCollectionTicker.C: + createVolumeMetricsJobs(&workerPool, discoveryService, databaseService, collectorFactory, fbVolumeMetricsCollectionFrequency, common.FlashBlade) + break + case <-dataRetentionTicker.C: + createDataRetentionJobs(&workerPool, databaseService) + break + } + } +} + +func createArrayMetricsJobs(workerPool *workerpool.Pool, discoveryService resources.ArrayDiscovery, databaseService metrics.Database, collectorFactory resources.CollectorFactory, collectionPeriod time.Duration) { + if discoveryService == nil { + log.Error("Discovery service is nil, stopping") + return + } + if databaseService == nil { + log.Error("Database service is nil, stopping") + return + } + + log.Trace("Starting to fetch arrays from discovery service") + arrays, err := discoveryService.GetArrays() + + if err != nil { + log.WithError(err).Error("Error fetching array list, skipping this iteration") + return + } + log.WithField("arrays", arrays).Trace("Fetched array list") + + for _, arrayStruct := range arrays { + log.WithField("array", arrayStruct).Trace("Enqueueing array metrics collect job for array") + workerPool.Enqueue(&jobs.ArrayMetricCollectJob{TargetArray: arrayStruct, CollectorFactory: collectorFactory, TargetDatabase: databaseService, TargetPool: workerPool}, collectionPeriod) + log.WithField("array", arrayStruct).Trace("Finished array enqueueing metrics collect job for array") + } + log.Trace("Array loop completed") +} + +func createVolumeMetricsJobs(workerPool *workerpool.Pool, discoveryService resources.ArrayDiscovery, databaseService metrics.Database, collectorFactory resources.CollectorFactory, collectionPeriod time.Duration, arrayType string) { + if discoveryService == nil { + log.Error("Discovery service is nil, stopping") + return + } + if databaseService == nil { + log.Error("Database service is nil, stopping") + return + } + + log.Trace("Starting to fetch arrays from discovery service") + arrays, err := discoveryService.GetArrays() + + if err != nil { + log.WithError(err).Error("Error fetching array list, skipping this iteration") + return + } + log.WithField("arrays", arrays).Trace("Fetched array list") + + for _, arrayStruct := range arrays { + if arrayStruct.DeviceType == arrayType { + log.WithField("array", arrayStruct).Trace("Enqueueing volume metrics collect job for array") + workerPool.Enqueue(&jobs.ArrayVolumeMetricCollectJob{TargetArray: arrayStruct, CollectorFactory: collectorFactory, TargetDatabase: databaseService, TargetPool: workerPool, TimeWindow: int64(collectionPeriod.Seconds())}, collectionPeriod) + log.WithField("array", arrayStruct).Trace("Finished enqueueing volume metrics collect job for array") + } + } + log.Trace("Array loop completed") +} + +func createDataRetentionJobs(workerPool *workerpool.Pool, databaseService metrics.Database) { + log.Info("Beginning data retention enforcement") + workerPool.Enqueue(&jobs.MetricCleanupJob{TargetDatabase: databaseService, MaxAgeInDays: metricsClientEnvConf.MetricsRetentionPeriod}, time.Hour) // Give it an hour to run, so it almost certainly will + log.Trace("Metrics cleanup job enqueued, enqueueing alerts cleanup job") + workerPool.Enqueue(&jobs.AlertCleanupJob{TargetDatabase: databaseService, MaxAgeInDays: metricsClientEnvConf.AlertsRetentionPeriod}, time.Hour) // Give it an hour to run, so it almost certainly will + log.Trace("Alerts cleanup job enqueued") + workerPool.Enqueue(&jobs.ErrorLogCleanupJob{TargetDatabase: databaseService, MaxAgeInDays: metricsClientEnvConf.ErrorLogRetentionPeriod}, time.Hour) + log.Trace("Error log cleanup job enqueued") + workerPool.Enqueue(&jobs.TimerLogCleanupJob{TargetDatabase: databaseService, MaxAgeInDays: metricsClientEnvConf.StageTimerRetentionPeriod}, time.Hour) + log.Trace("Stage timer log cleanup job enqueued") +} diff --git a/cmd/monitor-server/env.go b/cmd/monitor-server/env.go new file mode 100644 index 00000000..70d95327 --- /dev/null +++ b/cmd/monitor-server/env.go @@ -0,0 +1,44 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "github.com/caarlos0/env" + log "github.com/sirupsen/logrus" +) + +var ( + monitorServerEnv *MonitorServerEnvironmentVariables +) + +// MonitorServerEnvironmentVariables represent any environment variables that can be parsed +// for the monitor server +type MonitorServerEnvironmentVariables struct { + ElasticHost string `env:"ELASTIC_HOST" envDefault:"localhost:9200"` + MonitorPeriod int `env:"MONITOR_PERIOD" envDefault:"15"` + WorkerPoolThreads int `env:"WORKER_THREADS" envDefault:"10"` // Reasonable defaults for most workloads + WorkerPoolBufferLength int `env:"WORKER_BUFFER_LENGTH" envDefault:"25"` +} + +func parseMonitorServerEnvironmentVariables() error { + log.WithField("config", monitorServerEnv).Info("Initializing monitor server environment variables") + monitorServerEnv = new(MonitorServerEnvironmentVariables) + err := env.Parse(monitorServerEnv) + if err != nil { + return err + } + log.WithField("config", monitorServerEnv).Info("Done initializing monitor server environment variables") + return nil +} diff --git a/cmd/monitor-server/main.go b/cmd/monitor-server/main.go new file mode 100644 index 00000000..f3bc65d6 --- /dev/null +++ b/cmd/monitor-server/main.go @@ -0,0 +1,109 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "os" + "time" + + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/apiserver" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/array" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/clients/elastic" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/hooks" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/jobs" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/resources" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/common/workerpool" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/logger" + + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/version" + log "github.com/sirupsen/logrus" +) + +const ( + sourceName = "monitor-server" +) + +func main() { + log.SetLevel(log.TraceLevel) + log.SetFormatter(logger.CensorAPITokensFromFormatter(&log.TextFormatter{})) + log.SetReportCaller(true) + + log.WithFields(log.Fields{ + "version": version.Get(), + }).Info("Starting Monitor service") + + err := parseMonitorServerEnvironmentVariables() + if err != nil { + log.WithError(err).Fatal("Error loading server environment variables, exiting...") + os.Exit(1) + return + } + + apiServerConn := apiserver.NewConnection("http://pure1-unplugged-api-server") + discoveryService := apiServerConn + metadataConn := apiServerConn + deviceFactory := array.NewRESTFactory(apiServerConn) + + databaseService, err := elastic.InitializeClient(monitorServerEnv.ElasticHost, 0, time.Second*5) + if err != nil { + log.WithError(err).Fatal("Error initializing elastic client, exiting...") + os.Exit(1) + return + } + + timerHook, err := hooks.NewStageTimerHook(sourceName, databaseService) + if err != nil { + log.WithError(err).Fatal("Error creating StageTimerHook, exiting...") + os.Exit(1) + return + } + errorHook, err := hooks.NewErrorLogHook(sourceName, []log.Level{log.WarnLevel, log.ErrorLevel, log.FatalLevel}, databaseService) + if err != nil { + log.WithError(err).Fatal("Error creating ErrorLogHook, exiting...") + os.Exit(1) + return + } + + log.AddHook(timerHook) + log.AddHook(errorHook) + + metricsCollectionTicker := time.NewTicker(time.Duration(monitorServerEnv.MonitorPeriod) * time.Second) + + workerPool := workerpool.CreateThreadPool(monitorServerEnv.WorkerPoolThreads, monitorServerEnv.WorkerPoolBufferLength) + + for { + select { + case <-metricsCollectionTicker.C: + createMonitorJobs(discoveryService, deviceFactory, metadataConn, workerPool) + break + } + } +} + +func createMonitorJobs(discoveryService resources.ArrayDiscovery, deviceFactory resources.CollectorFactory, metadataConnection resources.ArrayMetadata, pool workerpool.Pool) { + devices, err := discoveryService.GetArrays() + if err != nil { + log.WithError(err).Error("Error getting devices from discovery service, skipping this iteration") + return + } + for _, device := range devices { + log.WithFields(device.GetLogFields(true)).Trace("Enqueueing monitor check job for device") + pool.Enqueue(&jobs.MonitorCheckJob{ + DeviceInfo: device, + DeviceFactory: deviceFactory, + Metadata: metadataConnection, + }, time.Duration(monitorServerEnv.MonitorPeriod)*time.Second) + } +} diff --git a/cmd/puctl/infra/deletepod.go b/cmd/puctl/infra/deletepod.go new file mode 100644 index 00000000..f71e9ee8 --- /dev/null +++ b/cmd/puctl/infra/deletepod.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func deletePodCommand() *cobra.Command { + cmd := cli.BuildCommand( + "delete-pod", + "Delete kubernetes pod(s)", + "Deletes kubernetes pod(s) based on the given filter. This usually isn't harmful because the pods will be regenerated automatically.", + infra.DeletePod, + ) + + return cmd +} diff --git a/cmd/puctl/infra/infra.go b/cmd/puctl/infra/infra.go new file mode 100644 index 00000000..547e9110 --- /dev/null +++ b/cmd/puctl/infra/infra.go @@ -0,0 +1,46 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +// Command is the main command for the "infra" group of commands +func Command() *cobra.Command { + subcmds := []*cobra.Command{ + initCommand(), + kubeCommand(), + resetCommand(), + statusCommand(), + upgradeCommand(), + versionCommand(), + repoCommand(), + deletePodCommand(), + packLogsCommand(), + } + + cmd := cli.BuildCommand( + "infra", + "Pure1 Unplugged App Infrastructure Tools", + "Pure1 Unplugged App Infrastructure Tools for configuration, deployment, troubleshooting, etc", + nil, + ) + + cmd.AddCommand(subcmds...) + + return cmd +} diff --git a/cmd/puctl/infra/init.go b/cmd/puctl/infra/init.go new file mode 100644 index 00000000..52a68770 --- /dev/null +++ b/cmd/puctl/infra/init.go @@ -0,0 +1,31 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func initCommand() *cobra.Command { + cmd := cli.BuildCommand("init", + "Initialize Pure1 Unplugged infrastructure", + "Setup required system settings followed by application platform (kubernetes) to run Pure1 Unplugged", + infra.Initialize, + ) + + return cmd +} diff --git a/cmd/puctl/infra/kube.go b/cmd/puctl/infra/kube.go new file mode 100644 index 00000000..e4c51151 --- /dev/null +++ b/cmd/puctl/infra/kube.go @@ -0,0 +1,31 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func kubeCommand() *cobra.Command { + cmd := cli.BuildCommand("kube", + "Shim to kubectl using local credentials", + "CLI tools to manage the application platform (kubernetes) to run Pure1 Unplugged.\n\n**HINT: use '--' before passing args for kubectl, ex: 'puctl infra kube -- get pods --all-namespaces'", + infra.KubeCTL, + ) + + return cmd +} diff --git a/cmd/puctl/infra/packlogs.go b/cmd/puctl/infra/packlogs.go new file mode 100644 index 00000000..2d0027ec --- /dev/null +++ b/cmd/puctl/infra/packlogs.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func packLogsCommand() *cobra.Command { + cmd := cli.BuildCommand( + "packlogs", + "Package Pure1 Unplugged logs", + "Packages the logs from all of the Pure1 Unplugged Kubernetes pods into a tarball for support purposes.", + infra.PackLogs, + ) + + return cmd +} diff --git a/cmd/puctl/infra/repo.go b/cmd/puctl/infra/repo.go new file mode 100644 index 00000000..56323fff --- /dev/null +++ b/cmd/puctl/infra/repo.go @@ -0,0 +1,59 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func repoCommand() *cobra.Command { + subcmds := []*cobra.Command{ + enableExternalRepoCommand(), + disableExternalRepoCommand(), + enablePure1UnpluggedRepoCommand(), + disablePure1UnpluggedRepoCommand(), + } + + cmd := cli.BuildCommand("repo", "Wrapper to manage repos", "CLI tools to manage Yum repos for both Pure1 Unplugged and external packages. Use this if you need to install a package that isn't available.", nil) + cmd.AddCommand(subcmds...) + + return cmd +} + +func enableExternalRepoCommand() *cobra.Command { + cmd := cli.BuildCommand("enable-external", "Enable external repos", "Enables all external repos to allow installing packages from outside the provided set with Pure1 Unplugged. It is recommended to disable these after you're done to ensure compatibility is maintained.", infra.EnableExternalRepos) + + return cmd +} + +func disableExternalRepoCommand() *cobra.Command { + cmd := cli.BuildCommand("disable-external", "Disable external repos", "Disables all external repos to prohibit installing packages from outside the provided set with Pure1 Unplugged.", infra.DisableExternalRepos) + + return cmd +} + +func enablePure1UnpluggedRepoCommand() *cobra.Command { + cmd := cli.BuildCommand("enable-pure1-unplugged", "Enable Pure1 Unplugged repo", "Enables the Pure1 Unplugged repo to allow updating. Note that this requires a Pure1 Unplugged image to be mounted in /media/Pure1-Unplugged_x86_64.", infra.EnablePure1UnpluggedRepo) + + return cmd +} + +func disablePure1UnpluggedRepoCommand() *cobra.Command { + cmd := cli.BuildCommand("disable-pure1-unplugged", "Disable Pure1 Unplugged repo", "Disables the Pure1 Unplugged repo. This is helpful if it's enabled and you can't update other packages because there's no Pure1 Unplugged repo present.", infra.DisablePure1UnpluggedRepo) + + return cmd +} diff --git a/cmd/puctl/infra/reset.go b/cmd/puctl/infra/reset.go new file mode 100644 index 00000000..59dfc964 --- /dev/null +++ b/cmd/puctl/infra/reset.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func resetCommand() *cobra.Command { + cmd := cli.BuildCommand( + "reset", + "Reset Pure1 Unplugged infrastructure", + "Reset application platform (kubernetes) to run Pure1 Unplugged. Best effort to clean up.", + infra.Reset, + ) + + return cmd +} diff --git a/cmd/puctl/infra/status.go b/cmd/puctl/infra/status.go new file mode 100644 index 00000000..c8c87207 --- /dev/null +++ b/cmd/puctl/infra/status.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func statusCommand() *cobra.Command { + cmd := cli.BuildCommand( + "status", + "See current Status of Pure1 Unplugged infrastructure", + "See current status of system settings and application platform (kubernetes) used by Pure1 Unplugged", + infra.Status, + ) + + return cmd +} diff --git a/cmd/puctl/infra/upgrade.go b/cmd/puctl/infra/upgrade.go new file mode 100644 index 00000000..e1570628 --- /dev/null +++ b/cmd/puctl/infra/upgrade.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func upgradeCommand() *cobra.Command { + cmd := cli.BuildCommand( + "upgrade", + "Upgrade Pure1 Unplugged infrastructure", + "Upgrade required system settings followed by application platform (kubernetes) to run Pure1 Unplugged", + infra.Upgrade, + ) + + return cmd +} diff --git a/cmd/puctl/infra/version.go b/cmd/puctl/infra/version.go new file mode 100644 index 00000000..16d42dab --- /dev/null +++ b/cmd/puctl/infra/version.go @@ -0,0 +1,31 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package infra + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func versionCommand() *cobra.Command { + cmd := cli.BuildCommand("version", + "Show version information about the app infrastructure", + "Show version information about the application platform (kubernetes) to run Pure1 Unplugged", + infra.Version, + ) + + return cmd +} diff --git a/cmd/puctl/main.go b/cmd/puctl/main.go new file mode 100644 index 00000000..9fc9529b --- /dev/null +++ b/cmd/puctl/main.go @@ -0,0 +1,34 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "github.com/spf13/cobra" + "math/rand" + "os" + "time" +) + +func main() { + cobra.OnInitialize(initialize) + rand.Seed(time.Now().UnixNano()) + cmd := initRootCommand() + err := cmd.Execute() + if err != nil { + fmt.Printf("Error: %s\n", err.Error()) + os.Exit(1) + } +} diff --git a/cmd/puctl/pectl.go b/cmd/puctl/pectl.go new file mode 100644 index 00000000..8c8f1028 --- /dev/null +++ b/cmd/puctl/pectl.go @@ -0,0 +1,146 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/PureStorage-OpenConnect/pure1-unplugged/cmd/puctl/infra" + "github.com/PureStorage-OpenConnect/pure1-unplugged/cmd/puctl/pure1unplugged" + "github.com/PureStorage-OpenConnect/pure1-unplugged/cmd/puctl/upgrade" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/config" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/version" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +const ( + defaultConfig = "/etc/pure1-unplugged/config.yaml" +) + +// config file for puctl +var cfgFile string + +var logFile string + +func initRootCommand() *cobra.Command { + subCmds := []*cobra.Command{ + infra.Command(), + pure1unplugged.Command(), + upgrade.Command(), + } + + desc := fmt.Sprintf("Pure1 Unplugged CLI - %s", version.Get()) + rootCmd := cli.BuildCommand("puctl", desc, desc, nil) + + // Hook the sub commands onto the root command + rootCmd.AddCommand(subCmds...) + + // Add in some sweet bash completion generator commands + completionCmd := getCompletionCmd(rootCmd) + rootCmd.AddCommand(completionCmd) + + rootCmd.PersistentFlags().StringVarP(&logFile, "logfile", "l", "", "path to log file, if set to '' (default) a random tmp file is used") + rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", defaultConfig, "path to config.yaml") + + return rootCmd +} + +// Setup logging and config +func initialize() { + if logFile == "" { + logFile = filepath.Join("/tmp/pure1-unplugged/", util.RandomString(10)+".log") + } + + fmt.Printf("\nLogging to %s\n\n", logFile) + + logDir := filepath.Dir(logFile) + err := os.MkdirAll(logDir, os.ModeDir) + if err != nil { + fmt.Printf("Unable to create log directory %s: %s\n", logDir, err.Error()) + os.Exit(1) + } + + logFileH, err := os.Create(logFile) + if err != nil { + fmt.Printf("Unable to open log file %s: %s\n", logDir, err.Error()) + os.Exit(1) + } + + // Add a hook to close our log file + logrus.RegisterExitHandler(func() { + if logFileH != nil { + logFileH.Close() + } + }) + + // Set all log output to go to our file, disable colors, and ensure timestamps are present + logrus.SetOutput(logFileH) + logrus.SetFormatter(&logrus.TextFormatter{DisableColors: true, FullTimestamp: true}) + + // Always log at debug level + logrus.SetLevel(logrus.DebugLevel) + + // See config options and defaults in pkg/puctl/config/config.go + // We just do the viper-related stuff in here + for k, v := range config.Defaults { + viper.SetDefault(k, v) + } + + logrus.Debugf("Using config: %s\n", cfgFile) + viper.SetConfigFile(cfgFile) + + if err := viper.ReadInConfig(); err != nil { + logrus.Errorf("Can't read config: %s", err) + os.Exit(1) + } +} + +// getCompletionCmd adds a 'completion' sub command to puctl which will generate bash command +// autocomplete script(s). +func getCompletionCmd(rootCmd *cobra.Command) *cobra.Command { + var completionCmd = &cobra.Command{ + Use: "completion OUTPUT_FILE", + Args: cobra.MinimumNArgs(1), + Short: "Generates bash completion scripts", + Long: `To load completion run + +. <(cat OUTPUT_FILE) + +To configure your bash shell to load completions for each session add to your bashrc + +# ~/.bashrc or ~/.profile +. <(cat OUTPUT_FILE) + +Alternatively just copy it to + +/etc/bash_completion.d/ + +`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Saving completion script to " + args[0]) + err := rootCmd.GenBashCompletionFile(args[0]) + if err != nil { + fmt.Printf("ERROR saving completion script: %s\n", err.Error()) + } + }, + } + return completionCmd +} diff --git a/cmd/puctl/pure1unplugged/install.go b/cmd/puctl/pure1unplugged/install.go new file mode 100644 index 00000000..41c4805b --- /dev/null +++ b/cmd/puctl/pure1unplugged/install.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pure1unplugged + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/pure1unplugged" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func installCommand() *cobra.Command { + cmd := cli.BuildCommand( + "install", + "Install Pure1 Unplugged Application", + "Install Pure1 Unplugged application", + pure1unplugged.Install, + ) + + return cmd +} diff --git a/cmd/puctl/pure1unplugged/pure1-unplugged.go b/cmd/puctl/pure1unplugged/pure1-unplugged.go new file mode 100644 index 00000000..4ce5e38b --- /dev/null +++ b/cmd/puctl/pure1unplugged/pure1-unplugged.go @@ -0,0 +1,42 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pure1unplugged + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +// Command is the main command for the "pure1unplugged" group of commands +func Command() *cobra.Command { + subcmds := []*cobra.Command{ + installCommand(), + resetCommand(), + statusCommand(), + upgradeCommand(), + versionCommand(), + } + + cmd := cli.BuildCommand( + "pure1-unplugged", + "Pure1 Unplugged Application Tools", + "Pure1 Unplugged Application Tools for configuration, deployment, troubleshooting, etc", + nil, + ) + + cmd.AddCommand(subcmds...) + + return cmd +} diff --git a/cmd/puctl/pure1unplugged/status.go b/cmd/puctl/pure1unplugged/status.go new file mode 100644 index 00000000..cd5d4e9d --- /dev/null +++ b/cmd/puctl/pure1unplugged/status.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pure1unplugged + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/pure1unplugged" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func statusCommand() *cobra.Command { + cmd := cli.BuildCommand( + "status", + "Display Pure1 Unplugged status", + "Show current Pure1 Unplugged Application status", + pure1unplugged.Status, + ) + + return cmd +} diff --git a/cmd/puctl/pure1unplugged/uninstall.go b/cmd/puctl/pure1unplugged/uninstall.go new file mode 100644 index 00000000..92e3aee5 --- /dev/null +++ b/cmd/puctl/pure1unplugged/uninstall.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pure1unplugged + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/pure1unplugged" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func resetCommand() *cobra.Command { + cmd := cli.BuildCommand( + "uninstall", + "Uninstall Pure1 Unplugged Application", + "Uninstall Pure1 Unplugged Application", + pure1unplugged.Uninstall, + ) + + return cmd +} diff --git a/cmd/puctl/pure1unplugged/upgrade.go b/cmd/puctl/pure1unplugged/upgrade.go new file mode 100644 index 00000000..e192fef5 --- /dev/null +++ b/cmd/puctl/pure1unplugged/upgrade.go @@ -0,0 +1,32 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pure1unplugged + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/pure1unplugged" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func upgradeCommand() *cobra.Command { + cmd := cli.BuildCommand( + "upgrade", + "Upgrade Pure1 Unplugged Application", + "Upgrade the currently running Pure1 Unplugged application", + pure1unplugged.Upgrade, + ) + + return cmd +} diff --git a/cmd/puctl/pure1unplugged/version.go b/cmd/puctl/pure1unplugged/version.go new file mode 100644 index 00000000..201284d5 --- /dev/null +++ b/cmd/puctl/pure1unplugged/version.go @@ -0,0 +1,31 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pure1unplugged + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/pure1unplugged" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func versionCommand() *cobra.Command { + cmd := cli.BuildCommand("version", + "Show version information about Pure1 Unplugged", + "Show version information about Pure1 Unplugged", + pure1unplugged.Version, + ) + + return cmd +} diff --git a/cmd/puctl/upgrade/mount.go b/cmd/puctl/upgrade/mount.go new file mode 100644 index 00000000..88a098a4 --- /dev/null +++ b/cmd/puctl/upgrade/mount.go @@ -0,0 +1,41 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package upgrade + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/upgrade" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func mountCommand() *cobra.Command { + cmd := cli.BuildCommand("mount-iso", + "Mount Pure1 Unplugged Upgrade ISO", + "Mounts an upgrade .iso from a given file. Note that mounting this disk through your VM infrastructure as a disk is preferred, but this is an alternative if you are unable to do so.", + upgrade.Mount, + ) + + return cmd +} + +func unmountCommand() *cobra.Command { + cmd := cli.BuildCommand("unmount-iso", + "Unmount Pure1 Unplugged Upgrade ISO", + "Unmounts an upgrade .iso that was previously mounted by using puctl upgrade mount-iso [file]", + upgrade.Unmount, + ) + + return cmd +} diff --git a/cmd/puctl/upgrade/upgrade.go b/cmd/puctl/upgrade/upgrade.go new file mode 100644 index 00000000..08f687ab --- /dev/null +++ b/cmd/puctl/upgrade/upgrade.go @@ -0,0 +1,40 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package upgrade + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +// Command is the main command for the "upgrade" group of commands +func Command() *cobra.Command { + subcmds := []*cobra.Command{ + mountCommand(), + unmountCommand(), + yumUpgradeCommand(), + } + + cmd := cli.BuildCommand( + "upgrade", + "Pure1 Unplugged App Upgrade Tools", + "Pure1 Unplugged App Upgrade Tools for mounting upgrade .iso files and updating packages", + nil, + ) + + cmd.AddCommand(subcmds...) + + return cmd +} diff --git a/cmd/puctl/upgrade/yum.go b/cmd/puctl/upgrade/yum.go new file mode 100644 index 00000000..c18d2540 --- /dev/null +++ b/cmd/puctl/upgrade/yum.go @@ -0,0 +1,31 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package upgrade + +import ( + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/puctl/upgrade" + "github.com/PureStorage-OpenConnect/pure1-unplugged/pkg/util/cli" + "github.com/spf13/cobra" +) + +func yumUpgradeCommand() *cobra.Command { + cmd := cli.BuildCommand("yum-upgrade", + "Upgrades the Pure1 Unplugged yum package", + "Upgrades the Pure1 Unplugged package using yum. Use this once you've mounted an upgrade .iso either as a disk or using 'puctl upgrade mount-iso [file]'.", + upgrade.YumUpgrade, + ) + + return cmd +} diff --git a/deploy/config.yaml b/deploy/config.yaml new file mode 100644 index 00000000..fd592e9e --- /dev/null +++ b/deploy/config.yaml @@ -0,0 +1,65 @@ +global: + # publicAddress is the public FQDN or IP address where pure1-unplugged will be reached. + # it is highly recommended to use an FQDN in case the IP address shifts over time. + # Ensure that this is resolvable by both the Pure1 Unplugged host and clients wanting to + # connect to it. + # If this changes the Pure1 Unplugged application must to be re-installed to pick up the change. + publicAddress: pure1-unplugged.example.com + + # The pod and service CIDR's will be used for the application infrastructure to + # run containers and their associated services on. They must be >=16 sized and + # cannot overlap with each other or real networks. They should be internal only. + # !! If these change the app infrastructure must be reset and initialized !! + #podCIDR: "192.168.0.0/16" + #serviceCIDR: "10.96.0.0/12" + + # If set to true the installer will generate self-signed SSL cert and key, overriding the + # settings for sslCertFile and sslKeyFile. If using the customized key and cert files this + # must be set to false! If set to true it will overwrite the files at those locations. + #createSelfSignedCerts: true + + # The SSL cert and key file locations are used by puctl when deploying to create + # the secrets used by the ingress server to do HTTPS termination. + # If these change the Pure1 Unplugged application should be re-installed to pick up the change. + #sslCertFile: /etc/pure1-unplugged/ssl/pure1-unplugged.crt + #sslKeyFile: /etc/pure1-unplugged/ssl/pure1-unplugged.key + + pure1unplugged: + # Use this to specify how long to keep metrics for devices and volumes, in days. Defaults + # to 31 days/1 month + metricRetentionPeriod: 31 + + # Use this to specify how long alerts should be kept before they are discarded, in days. Defaults to 365 days + alertRetentionPeriod: 365 + + # Use this to specify how long to keep error/warning log lines before they are discarded, in days. Defaults to 1 day + errorLogRetentionPeriod: 1 + + # Use this to specify how long to keep timer logs before they are discarded, in days. Defaults to 1 day. + # Highly recommended to keep this value low as this is a very large amount of data. + timerLogRetentionPeriod: 1 + + # Use this to specify how often FlashArray volume metrics information should be collected, in seconds. Defaults to 30 seconds. + faVolumeCollectionPeriod: 30 + + # Use this to specify how often FlashArray volume (filesystem) metrics information should be collected, in seconds. Defaults to 300 seconds. + # Note that anything less than 300 seconds may have performance concerns for the FlashBlade and Pure1 Unplugged. + fbVolumeCollectionPeriod: 300 + +dex: + # See https://github.com/dexidp/dex for info about how to configure Dex, primarily the different connectors + enablePasswordDBConnector: true + + # Note: this key must always be present. If you want no static passwords, simply write it as + # staticPasswords: [] + staticPasswords: + - email: "admin@example.com" + # bcrypt hash of the string "password" + hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" + username: "admin" + userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" + + connectors: + - type: mockCallback + id: mock + name: Example diff --git a/deploy/helm/pure1-unplugged/.helmignore b/deploy/helm/pure1-unplugged/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/Chart.yaml b/deploy/helm/pure1-unplugged/Chart.yaml new file mode 100644 index 00000000..fc0687e8 --- /dev/null +++ b/deploy/helm/pure1-unplugged/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "@PURE1_UNPLUGGED_VERSION@" +description: "Installs Pure1 Unplugged." +name: pure1-unplugged +version: "@PURE1_UNPLUGGED_VERSION@" diff --git a/deploy/helm/pure1-unplugged/charts/api-server/.helmignore b/deploy/helm/pure1-unplugged/charts/api-server/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/api-server/Chart.yaml b/deploy/helm/pure1-unplugged/charts/api-server/Chart.yaml new file mode 100644 index 00000000..3924972c --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: api-server +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/api-server/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/api-server/templates/NOTES.txt new file mode 100644 index 00000000..07157e6f --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/templates/NOTES.txt @@ -0,0 +1,19 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "api-server.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ template "api-server.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "api-server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "api-server.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/api-server/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/api-server/templates/_helpers.tpl new file mode 100644 index 00000000..25d39265 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "api-server.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "api-server.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "api-server.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/api-server/templates/deployment.yaml b/deploy/helm/pure1-unplugged/charts/api-server/templates/deployment.yaml new file mode 100644 index 00000000..c4191fc1 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/templates/deployment.yaml @@ -0,0 +1,49 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "api-server.fullname" . }} + labels: + app: {{ template "api-server.name" . }} + chart: {{ template "api-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "api-server.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "api-server.name" . }} + release: {{ .Release.Name }} + spec: + serviceAccountName: secret-manager + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.global.pure1unplugged.image.repository }}:{{ .Values.global.pure1unplugged.image.tag }}" + imagePullPolicy: {{ .Values.global.pure1unplugged.image.pullPolicy }} + command: [ "pure1-unplugged-api-server" ] + env: + - name: ELASTIC_CLIENT_HOST + value: pure1-unplugged-elasticsearch-client:9200 + ports: + - name: ds-api-port + port: 8080 + containerPort: 8080 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/api-server/templates/ingress.yaml b/deploy/helm/pure1-unplugged/charts/api-server/templates/ingress.yaml new file mode 100644 index 00000000..2fd9a90f --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/templates/ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "api-server.fullname" . -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ template "api-server.name" . }} + chart: {{ template "api-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /$1 + ingress.kubernetes.io/secure-backends: "false" + nginx.ingress.kubernetes.io/auth-url: "https://$host/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/auth/login" +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /api/?(.*) + backend: + serviceName: {{ $fullName }} + servicePort: ds-api-port +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/api-server/templates/service.yaml b/deploy/helm/pure1-unplugged/charts/api-server/templates/service.yaml new file mode 100644 index 00000000..e5d0e9db --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "api-server.fullname" . }} + labels: + app: {{ template "api-server.name" . }} + chart: {{ template "api-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + ports: + - port: {{ .Values.service.port }} + targetPort: ds-api-port + protocol: TCP + name: http + selector: + app: {{ template "api-server.name" . }} + release: {{ .Release.Name }} diff --git a/deploy/helm/pure1-unplugged/charts/api-server/values.yaml b/deploy/helm/pure1-unplugged/charts/api-server/values.yaml new file mode 100644 index 00000000..7d8ce14d --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/api-server/values.yaml @@ -0,0 +1,29 @@ +# Default values for api-server. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +service: + port: 80 + +ingress: + enabled: true + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/.helmignore b/deploy/helm/pure1-unplugged/charts/auth-server/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/Chart.yaml b/deploy/helm/pure1-unplugged/charts/auth-server/Chart.yaml new file mode 100644 index 00000000..27f6cfde --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: auth-server +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/auth-server/templates/NOTES.txt new file mode 100644 index 00000000..e69de29b diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/auth-server/templates/_helpers.tpl new file mode 100644 index 00000000..c877c9cb --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "auth-server.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "auth-server.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "auth-server.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/templates/api-token-ingress.yaml b/deploy/helm/pure1-unplugged/charts/auth-server/templates/api-token-ingress.yaml new file mode 100644 index 00000000..ee27138f --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/templates/api-token-ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "auth-server.fullname" . -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }}-api-token + labels: + app: {{ template "auth-server.name" . }} + chart: {{ template "auth-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + kubernetes.io/ingress.class: nginx + ingress.kubernetes.io/secure-backends: "false" + nginx.ingress.kubernetes.io/auth-url: "https://$host/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/auth/login" + nginx.ingress.kubernetes.io/rewrite-target: /api-token$1 +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /auth/api-token(/?.*) + backend: + serviceName: {{ $fullName }} + servicePort: http +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/templates/deployment.yaml b/deploy/helm/pure1-unplugged/charts/auth-server/templates/deployment.yaml new file mode 100644 index 00000000..3c46bb2c --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/templates/deployment.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "auth-server.fullname" . }} + labels: + app: {{ template "auth-server.name" . }} + chart: {{ template "auth-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "auth-server.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "auth-server.name" . }} + release: {{ .Release.Name }} + spec: + serviceAccountName: secret-manager + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.global.pure1unplugged.image.repository }}:{{ .Values.global.pure1unplugged.image.tag }}" + imagePullPolicy: {{ .Values.global.pure1unplugged.image.pullPolicy }} + command: [ "pure1-unplugged-auth-server" ] + env: + - name: OPENID_CONNECT_ISSUER_URL + value: https://{{ .Values.global.publicAddress }}/dex + - name: AUTH_SERVER_LISTEN_AT + value: http://:80 + - name: AUTH_SERVER_CALLBACK_URL + value: https://{{ .Values.global.publicAddress }}/auth/callback + - name: ELASTIC_HOST + value: pure1-unplugged-elasticsearch-client:9200 + ports: + - name: http + port: 80 + containerPort: 80 + protocol: TCP + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/templates/main-ingress.yaml b/deploy/helm/pure1-unplugged/charts/auth-server/templates/main-ingress.yaml new file mode 100644 index 00000000..b6e53333 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/templates/main-ingress.yaml @@ -0,0 +1,37 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "auth-server.fullname" . -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ template "auth-server.name" . }} + chart: {{ template "auth-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + kubernetes.io/ingress.class: nginx + ingress.kubernetes.io/secure-backends: "false" + nginx.ingress.kubernetes.io/rewrite-target: /$1 +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /auth/?(.*) + backend: + serviceName: {{ $fullName }} + servicePort: http +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/templates/service-account.yaml b/deploy/helm/pure1-unplugged/charts/auth-server/templates/service-account.yaml new file mode 100644 index 00000000..7712a7aa --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/templates/service-account.yaml @@ -0,0 +1,31 @@ +# The service account to add to the auth server pod +apiVersion: v1 +kind: ServiceAccount +metadata: + name: secret-manager +--- +# The role to allow secret CRUD +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + namespace: {{ .Release.Namespace }} + name: secret-rw +rules: + - apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "create", "delete", "update"] +--- +# Bind the role to the account +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: secret-service-account + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: secret-rw +subjects: +- kind: ServiceAccount + name: secret-manager + namespace: {{ .Release.Namespace }} diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/templates/service.yaml b/deploy/helm/pure1-unplugged/charts/auth-server/templates/service.yaml new file mode 100644 index 00000000..c4a14229 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "auth-server.fullname" . }} + labels: + app: {{ template "auth-server.name" . }} + chart: {{ template "auth-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "auth-server.name" . }} + release: {{ .Release.Name }} diff --git a/deploy/helm/pure1-unplugged/charts/auth-server/values.yaml b/deploy/helm/pure1-unplugged/charts/auth-server/values.yaml new file mode 100644 index 00000000..491c628f --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/auth-server/values.yaml @@ -0,0 +1,29 @@ +# Default values for auth-server. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +service: + port: 80 + +ingress: + enabled: true + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/deploy/helm/pure1-unplugged/charts/dex/.helmignore b/deploy/helm/pure1-unplugged/charts/dex/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/dex/Chart.yaml b/deploy/helm/pure1-unplugged/charts/dex/Chart.yaml new file mode 100644 index 00000000..5ba88031 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: Deploys dex in the cluster for authentication +name: dex +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/dex/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/dex/templates/NOTES.txt new file mode 100644 index 00000000..74430bac --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/templates/NOTES.txt @@ -0,0 +1,20 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range .Values.ingress.hosts }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "dex.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get svc -w {{ include "dex.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "dex.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}') + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ include "dex.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} + diff --git a/deploy/helm/pure1-unplugged/charts/dex/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/dex/templates/_helpers.tpl new file mode 100644 index 00000000..fa47488c --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "dex.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "dex.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "dex.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/dex/templates/configmap.yaml b/deploy/helm/pure1-unplugged/charts/dex/templates/configmap.yaml new file mode 100644 index 00000000..2f612055 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/templates/configmap.yaml @@ -0,0 +1,48 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "dex.fullname" . }} + labels: + app: {{ include "dex.name" . }} + chart: {{ include "dex.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + config.yaml: | + expiry: + idTokens: {{ .Values.tokenTTL }} + issuer: https://{{ .Values.global.publicAddress }}/dex + storage: + type: kubernetes + config: + inCluster: true + web: + http: 0.0.0.0:32000 + telemetry: + http: 0.0.0.0:5558 + + frontend: + theme: "pure" + + logger: + level: "debug" + format: "text" + + connectors: +{{ toYaml .Values.connectors | indent 10}} + + staticClients: + - id: pure1-unplugged + redirectURIs: + - https://{{ .Values.global.publicAddress }}/auth/callback + name: 'Pure1 Unplugged' + secret: ZXhhbXBsZS1hcHAtc2VjcmV0 + + {{- if .Values.staticPasswords }} + + enablePasswordDB: true + staticPasswords: +{{ toYaml .Values.staticPasswords | indent 8}} + {{- else }} + enablePasswordDB: false + {{- end }} \ No newline at end of file diff --git a/deploy/helm/pure1-unplugged/charts/dex/templates/deployment.yaml b/deploy/helm/pure1-unplugged/charts/dex/templates/deployment.yaml new file mode 100644 index 00000000..a7bffc06 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/templates/deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ include "dex.fullname" . }} + labels: + app: {{ include "dex.name" . }} + chart: {{ include "dex.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ include "dex.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ include "dex.name" . }} + release: {{ .Release.Name }} + spec: + serviceAccountName: {{ include "dex.fullname" . }} + volumes: + - name: config + configMap: + name: {{ include "dex.fullname" . }} + items: + - key: config.yaml + path: config.yaml + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.global.pure1unplugged.image.repository }}:{{ .Values.global.pure1unplugged.image.tag }}" + imagePullPolicy: {{ .Values.global.pure1unplugged.image.pullPolicy }} + command: ["/usr/local/bin/dex", "serve", "/etc/dex/cfg/config.yaml"] + ports: + - name: http + containerPort: 32000 + protocol: TCP + volumeMounts: + - name: config + mountPath: /etc/dex/cfg + {{- if .Values.enableGithubConnector}} + env: + - name: GITHUB_CLIENT_ID + valueFrom: + secretKeyRef: + name: github-client + key: client-id + - name: GITHUB_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: github-client + key: client-secret + {{- end}} + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/dex/templates/ingress.yaml b/deploy/helm/pure1-unplugged/charts/dex/templates/ingress.yaml new file mode 100644 index 00000000..4922c438 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/templates/ingress.yaml @@ -0,0 +1,36 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "dex.fullname" . -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ template "dex.name" . }} + chart: {{ template "dex.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + ingress.kubernetes.io/secure-backends: "false" +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /dex + backend: + serviceName: {{ $fullName }} + servicePort: http + +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/dex/templates/rbac.yaml b/deploy/helm/pure1-unplugged/charts/dex/templates/rbac.yaml new file mode 100644 index 00000000..4bd7f132 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/templates/rbac.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "dex.fullname" . }} + labels: + app: {{ include "dex.name" . }} + chart: {{ include "dex.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRole +metadata: + name: {{ include "dex.fullname" . }} + labels: + app: {{ include "dex.name" . }} + chart: {{ include "dex.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +rules: + - apiGroups: ["dex.coreos.com"] # API group created by dex + resources: ["*"] + verbs: ["*"] + - apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["create"] # To manage its own resources, dex must be able to create customresourcedefinitions +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: {{ include "dex.fullname" . }} + labels: + app: {{ include "dex.name" . }} + chart: {{ include "dex.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "dex.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "dex.fullname" . }} # Service account assigned to the dex pod, created above + namespace: {{ .Release.Namespace }} # The namespace dex is running in diff --git a/deploy/helm/pure1-unplugged/charts/dex/templates/service.yaml b/deploy/helm/pure1-unplugged/charts/dex/templates/service.yaml new file mode 100644 index 00000000..9e7218ed --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "dex.fullname" . }} + labels: + app: {{ include "dex.name" . }} + chart: {{ include "dex.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ include "dex.name" . }} + release: {{ .Release.Name }} diff --git a/deploy/helm/pure1-unplugged/charts/dex/values.yaml b/deploy/helm/pure1-unplugged/charts/dex/values.yaml new file mode 100644 index 00000000..e2406fae --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/dex/values.yaml @@ -0,0 +1,48 @@ +# Default values for dex. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +enablePasswordDBConnector: false + +tokenTTL: "1h" # Default to one hour + +connectors: [] # Placeholder: should be specified by user + +staticPasswords: [] # Placeholder: should be specified by user + +nameOverride: "" +fullnameOverride: "" + +service: + port: 80 + +ingress: + enabled: true + annotations: { + ingress.kubernetes.io/secure-backends: "false" + } + path: /dex + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/deploy/helm/pure1-unplugged/charts/elastic-setup/.helmignore b/deploy/helm/pure1-unplugged/charts/elastic-setup/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/elastic-setup/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/elastic-setup/Chart.yaml b/deploy/helm/pure1-unplugged/charts/elastic-setup/Chart.yaml new file mode 100644 index 00000000..18ecaaae --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/elastic-setup/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: elastic-setup +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/NOTES.txt new file mode 100644 index 00000000..e69de29b diff --git a/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/_helpers.tpl new file mode 100644 index 00000000..2138ad37 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "elastic-setup.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "elastic-setup.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "elastic-setup.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/elastic-pvs.yaml b/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/elastic-pvs.yaml new file mode 100644 index 00000000..f69f9fd2 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/elastic-pvs.yaml @@ -0,0 +1,39 @@ +kind: PersistentVolume +apiVersion: v1 +metadata: + name: elastic-master-pv-0 + labels: + app: {{ template "elastic-setup.name" . }} + chart: {{ template "elastic-setup.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + capacity: + storage: 4Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete + storageClassName: elastic-master-pv + hostPath: + path: "/mnt/elastic-master-pv-0" +--- +kind: PersistentVolume +apiVersion: v1 +metadata: + name: elastic-data-pv + labels: + app: {{ template "elastic-setup.name" . }} + chart: {{ template "elastic-setup.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + capacity: + storage: 10Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Delete + storageClassName: elastic-data-pv + hostPath: + path: "/mnt/elastic-data-pv" diff --git a/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/kibana-post-install.yaml b/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/kibana-post-install.yaml new file mode 100644 index 00000000..1a5ad299 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/elastic-setup/templates/kibana-post-install.yaml @@ -0,0 +1,32 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "elastic-setup.fullname" . }} + labels: + # The "heritage" label is used to track which tool deployed a given chart. + # It is useful for admins who want to see what releases a particular tool + # is responsible for. + heritage: {{ .Release.Service }} + # The "release" convention makes it easy to tie a release to all of the + # Kubernetes resources that were created as part of that release. + release: {{ .Release.Name }} + # This makes it easy to audit chart usage. + chart: {{ .Chart.Name }}-{{ .Chart.Version }} + app: {{ template "elastic-setup.name" . }} + product: "Pure1-Unplugged" +spec: + backoffLimit: 16 + activeDeadlineSeconds: 1800 + template: + metadata: + name: {{ template "elastic-setup.fullname" . }} + labels: + release: {{ .Release.Name }} + app: {{ template "elastic-setup.name" . }} + spec: + restartPolicy: "OnFailure" + containers: + - name: post-install-job + image: {{ .Values.global.pure1unplugged.image.repository }}:{{ .Values.global.pure1unplugged.image.tag }} + imagePullPolicy: {{ .Values.global.pure1unplugged.image.pullPolicy }} + command: [ "./kibana-files/kibana_setup.sh" ] diff --git a/deploy/helm/pure1-unplugged/charts/elastic-setup/values.yaml b/deploy/helm/pure1-unplugged/charts/elastic-setup/values.yaml new file mode 100644 index 00000000..e69de29b diff --git a/deploy/helm/pure1-unplugged/charts/elasticsearch-1.17.0.tgz b/deploy/helm/pure1-unplugged/charts/elasticsearch-1.17.0.tgz new file mode 100644 index 00000000..0cd68c92 Binary files /dev/null and b/deploy/helm/pure1-unplugged/charts/elasticsearch-1.17.0.tgz differ diff --git a/deploy/helm/pure1-unplugged/charts/kibana-1.1.2.tgz b/deploy/helm/pure1-unplugged/charts/kibana-1.1.2.tgz new file mode 100644 index 00000000..00f734b1 Binary files /dev/null and b/deploy/helm/pure1-unplugged/charts/kibana-1.1.2.tgz differ diff --git a/deploy/helm/pure1-unplugged/charts/metrics-client/.helmignore b/deploy/helm/pure1-unplugged/charts/metrics-client/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/metrics-client/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/metrics-client/Chart.yaml b/deploy/helm/pure1-unplugged/charts/metrics-client/Chart.yaml new file mode 100644 index 00000000..d8b7e2c7 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/metrics-client/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: metrics-client +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/metrics-client/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/metrics-client/templates/NOTES.txt new file mode 100644 index 00000000..e69de29b diff --git a/deploy/helm/pure1-unplugged/charts/metrics-client/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/metrics-client/templates/_helpers.tpl new file mode 100644 index 00000000..c447e673 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/metrics-client/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "metrics-client.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "metrics-client.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "metrics-client.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/metrics-client/templates/deployment.yaml b/deploy/helm/pure1-unplugged/charts/metrics-client/templates/deployment.yaml new file mode 100644 index 00000000..f81d0add --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/metrics-client/templates/deployment.yaml @@ -0,0 +1,59 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "metrics-client.fullname" . }} + labels: + app: {{ template "metrics-client.name" . }} + chart: {{ template "metrics-client.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ template "metrics-client.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "metrics-client.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.global.pure1unplugged.image.repository }}:{{ .Values.global.pure1unplugged.image.tag }}" + imagePullPolicy: {{ .Values.global.pure1unplugged.image.pullPolicy }} + command: ["pure1-unplugged-metrics-client"] + env: + - name: PURE_DISCOVERY_TYPE + value: pure1 + - name: PURE_DISCOVERY_PURE1_HOST + value: pure1-unplugged-api-server + - name: ELASTIC_HOST + value: pure1-unplugged-elasticsearch-client:9200 + - name: ELASTIC_METRICS_RETENTION_PERIOD + value: "{{ .Values.global.pure1unplugged.metricRetentionPeriod }}" + - name: ELASTIC_ALERTS_RETENTION_PERIOD + value: "{{ .Values.global.pure1unplugged.alertRetentionPeriod }}" + - name: ELASTIC_ERROR_LOG_RETENTION_PERIOD + value: "{{ .Values.global.pure1unplugged.errorLogRetentionPeriod }}" + - name: ELASTIC_STAGE_TIMER_RETENTION_PERIOD + value: "{{ .Values.global.pure1unplugged.timerLogRetentionPeriod }}" + - name: ELASTIC_FA_VOLUME_METRIC_COLLECTION_PERIOD + value: "{{ .Values.global.pure1unplugged.faVolumeCollectionPeriod }}" + - name: ELASTIC_FB_VOLUME_METRIC_COLLECTION_PERIOD + value: "{{ .Values.global.pure1unplugged.fbVolumeCollectionPeriod }}" + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/metrics-client/values.yaml b/deploy/helm/pure1-unplugged/charts/metrics-client/values.yaml new file mode 100644 index 00000000..a82cb183 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/metrics-client/values.yaml @@ -0,0 +1,21 @@ +# Default values for metrics-client. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/deploy/helm/pure1-unplugged/charts/monitor-server/.helmignore b/deploy/helm/pure1-unplugged/charts/monitor-server/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/monitor-server/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/monitor-server/Chart.yaml b/deploy/helm/pure1-unplugged/charts/monitor-server/Chart.yaml new file mode 100644 index 00000000..4cf46fef --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/monitor-server/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: monitor-server +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/monitor-server/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/monitor-server/templates/NOTES.txt new file mode 100644 index 00000000..e69de29b diff --git a/deploy/helm/pure1-unplugged/charts/monitor-server/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/monitor-server/templates/_helpers.tpl new file mode 100644 index 00000000..68427387 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/monitor-server/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "monitor-server.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "monitor-server.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "monitor-server.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/monitor-server/templates/deployment.yaml b/deploy/helm/pure1-unplugged/charts/monitor-server/templates/deployment.yaml new file mode 100644 index 00000000..cf7aa33a --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/monitor-server/templates/deployment.yaml @@ -0,0 +1,47 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "monitor-server.fullname" . }} + labels: + app: {{ template "monitor-server.name" . }} + chart: {{ template "monitor-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "monitor-server.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "monitor-server.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.global.pure1unplugged.image.repository }}:{{ .Values.global.pure1unplugged.image.tag }}" + imagePullPolicy: {{ .Values.global.pure1unplugged.image.pullPolicy }} + command: [ "pure1-unplugged-monitor-server" ] + env: + - name: PURE_DISCOVERY_TYPE + value: pure1 + - name: PURE_DISCOVERY_PURE1_HOST + value: pure1-unplugged-api-server + - name: ELASTIC_HOST + value: pure1-unplugged-elasticsearch-client:9200 + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/monitor-server/values.yaml b/deploy/helm/pure1-unplugged/charts/monitor-server/values.yaml new file mode 100644 index 00000000..1568c222 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/monitor-server/values.yaml @@ -0,0 +1,23 @@ +# Default values for monitor-server. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/deploy/helm/pure1-unplugged/charts/nginx-ingress-1.3.1.tgz b/deploy/helm/pure1-unplugged/charts/nginx-ingress-1.3.1.tgz new file mode 100644 index 00000000..1eb40fd7 Binary files /dev/null and b/deploy/helm/pure1-unplugged/charts/nginx-ingress-1.3.1.tgz differ diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/.helmignore b/deploy/helm/pure1-unplugged/charts/swagger-server/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/Chart.yaml b/deploy/helm/pure1-unplugged/charts/swagger-server/Chart.yaml new file mode 100644 index 00000000..4c997a12 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: swagger-server +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/api-server-swagger.yaml b/deploy/helm/pure1-unplugged/charts/swagger-server/api-server-swagger.yaml new file mode 100644 index 00000000..940db8f1 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/api-server-swagger.yaml @@ -0,0 +1,503 @@ +openapi: 3.0.0 +info: + title: Pure1 Unplugged API + description: The interface provided by the Pure1 Unplugged API Server + version: 0.0.1 +servers: + - url: / + description: This Pure1 Unplugged 2.0 instance +tags: + - name: Device Operations + description: Operations regarding the top-level devices + - name: Status Operations + description: Operations regarding device statuses + - name: Tag Operations + description: Operations regarding device tags +paths: + /api/arrays: + get: + summary: Returns a list of registered storage devices + tags: + - Device Operations + parameters: + - $ref: "#/components/parameters/idsParam" + - $ref: "#/components/parameters/namesParam" + - $ref: "#/components/parameters/modelsParam" + - $ref: "#/components/parameters/versionsParam" + - $ref: "#/components/parameters/limitParam" + - $ref: "#/components/parameters/offsetParam" + - $ref: "#/components/parameters/sortParam" + responses: + "200": + description: The search was successful + content: + application/json: + schema: + description: Collection of devices + type: object + properties: + response: + type: array + items: + $ref: "#/components/schemas/Device" + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" + post: + summary: Registers a new storage device + tags: + - Device Operations + requestBody: + description: The device to register + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DeviceRegistration" + responses: + "200": + description: The device was registered successfully + content: + application/json: + schema: + description: The registered device + $ref: "#/components/schemas/Device" + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" + patch: + summary: Modifies all storage devices matching the given query + tags: + - Device Operations + parameters: + - $ref: "#/components/parameters/idsParam" + - $ref: "#/components/parameters/namesParam" + - $ref: "#/components/parameters/modelsParam" + - $ref: "#/components/parameters/versionsParam" + requestBody: + description: The patch to apply + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/DevicePatch" + responses: + "200": + description: The patch was successful + content: + application/json: + schema: + description: Collection of devices + type: object + properties: + response: + type: array + items: + $ref: "#/components/schemas/Device" + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" + delete: + summary: Deletes all storage devices matching the given query. Note that this will fail on an empty query to avoid mass-destructive operations. + tags: + - Device Operations + parameters: + - $ref: "#/components/parameters/idsParam" + - $ref: "#/components/parameters/namesParam" + - $ref: "#/components/parameters/modelsParam" + - $ref: "#/components/parameters/versionsParam" + responses: + "200": + description: The deletion was successful + content: + application/json: + schema: + type: object + properties: + deletedCount: + description: The number of devices deleted + type: integer + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" + /api/arrays/status: + get: + summary: Returns a list of registered storage device statuses + tags: + - Status Operations + parameters: + - $ref: "#/components/parameters/idsParam" + - $ref: "#/components/parameters/namesParam" + - $ref: "#/components/parameters/modelsParam" + - $ref: "#/components/parameters/versionsParam" + - $ref: "#/components/parameters/limitParam" + - $ref: "#/components/parameters/offsetParam" + - $ref: "#/components/parameters/sortParam" + responses: + "200": + description: The registration was successful + content: + application/json: + schema: + description: Collection of device statuses + type: object + properties: + response: + type: array + items: + $ref: "#/components/schemas/DeviceStatus" + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" + /api/arrays/tags: + get: + summary: Returns a list of registered storage device tags + tags: + - Tag Operations + parameters: + - $ref: "#/components/parameters/idsParam" + - $ref: "#/components/parameters/namesParam" + - $ref: "#/components/parameters/modelsParam" + - $ref: "#/components/parameters/versionsParam" + - $ref: "#/components/parameters/limitParam" + - $ref: "#/components/parameters/offsetParam" + - $ref: "#/components/parameters/sortParam" + responses: + "200": + description: The search was successful + content: + application/json: + schema: + description: Collection of device tags + type: object + properties: + response: + type: array + items: + $ref: "#/components/schemas/DeviceTags" + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" + patch: + summary: Adds new tags and modifies existing tags on all devices matching the given query + tags: + - Tag Operations + parameters: + - $ref: "#/components/parameters/idsParam" + - $ref: "#/components/parameters/namesParam" + - $ref: "#/components/parameters/modelsParam" + - $ref: "#/components/parameters/versionsParam" + requestBody: + description: The tag patch to apply + required: true + content: + application/json: + schema: + description: Collection of device tag patches + type: object + properties: + tags: + type: array + items: + $ref: "#/components/schemas/DeviceTag" + responses: + "200": + description: The patch was successful + content: + application/json: + schema: + description: Collection of device tags + type: object + properties: + response: + type: array + items: + $ref: "#/components/schemas/DeviceTags" + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" + delete: + summary: Deletes the given tags from all devices matching the given query + tags: + - Tag Operations + parameters: + - $ref: "#/components/parameters/idsParam" + - $ref: "#/components/parameters/namesParam" + - $ref: "#/components/parameters/modelsParam" + - $ref: "#/components/parameters/versionsParam" + - name: tags + description: The tag keys to delete, as a comma-separated list + in: query + required: true + schema: + type: array + items: + type: string + responses: + "200": + description: The deletion was successful + content: + application/json: + schema: + description: Collection of device tags + type: object + properties: + response: + type: array + items: + $ref: "#/components/schemas/DeviceTags" + "400": + $ref: "#/components/responses/400Response" + "500": + $ref: "#/components/responses/500Response" +components: + parameters: + idsParam: + name: ids + description: The IDs to filter by, as a comma-separated list + in: query + schema: + type: array + items: + type: string + namesParam: + name: names + description: The names to filter by, as a comma-separated list. Wildcards are supported + in: query + schema: + type: array + items: + type: string + modelsParam: + name: models + description: The device models to filter by, as a comma-separated list. Wildcards are supported + in: query + schema: + type: array + items: + type: string + versionsParam: + name: versions + description: The versions to filter by, as a comma-separated list. Wildcards are supported + in: query + schema: + type: array + items: + type: string + limitParam: + name: limit + description: The maximum number of items to return + in: query + schema: + type: integer + minimum: 1 + offsetParam: + name: offset + description: The number of items to skip + in: query + schema: + type: integer + minimum: 0 + sortParam: + name: sort + description: How to sort the returned results. Add a hyphen at the end to sort descending, default is ascending. + in: query + schema: + type: string + responses: + 400Response: + description: Something in the input was invalid + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + 500Response: + description: Something went wrong in the server (such as a database connection error) + content: + application/json: + schema: + $ref: "#/components/schemas/ErrorResponse" + schemas: + Device: + description: Information about a specific device + type: object + required: + - id + - name + - mgmt_endpoint + - api_token + - device_type + - status + - model + - version + - _as_of + - _last_updated + properties: + id: + type: string + description: Globally unique device ID + name: + type: string + description: Device display name + mgmt_endpoint: + type: string + description: Address to access the device management portal through + nfs_endpoint: + type: string + description: Address to access the network file system through (required for FlashBlade only) + api_token: + type: string + description: API token to use to access the device + device_type: + type: string + description: The type of the device (either "FlashArray" or "FlashBlade") + status: + type: string + description: >- + Current status of the device. One of: { "Connecting", "Connected", + "Unable to connect. Error: [error message]"} + model: + type: string + description: >- + The model of the device. For example, "FlashBlade", "FA-405", etc. + version: + type: string + description: >- + The purity version running on the device. For example, "5.1.3", "4.9.5", or "2.3.3" + _as_of: + type: string + description: The last time the device was successfully pinged, in ISO 8601 format (yyyy-MM-ddTHH:mm:ss.SSS) + _last_updated: + type: string + description: >- + The last time information in this device was updated, in ISO 8601 + format (yyyy-MM-ddTHH:mm:ss.SSS) + DeviceRegistration: + description: Information to register an device + type: object + required: + - name + - mgmt_endpoint + - api_token + - device_type + properties: + name: + type: string + description: Device display name + mgmt_endpoint: + type: string + description: Address to access the device management portal through + api_token: + type: string + description: API token to use to access the device + device_type: + type: string + description: The type of the device (either "FlashArray" or "FlashBlade") + nfs_endpoint: + type: string + description: Address to access the network file system through (required for FlashBlade only) + DevicePatch: + description: Information to patch for a device/devices + type: object + properties: + name: + type: string + description: Device display name + mgmt_endpoint: + type: string + description: Address to access the device management portal through + nfs_endpoint: + type: string + description: Address to access the network file system through (required for FlashBlade only) + api_token: + type: string + description: API token to use to access the device + device_type: + type: string + description: The type of the device (either "FlashArray" or "FlashBlade") + status: + type: string + description: For internal modification only. + _as_of: + type: string + description: For internal modification only. + _last_updated: + type: string + description: For internal modification only. + DeviceStatus: + description: Information on the status of a specific device + type: object + required: + - id + - status + - _as_of + properties: + id: + type: string + description: Globally unique device ID + status: + type: string + description: >- + Current status of the device. One of: { 'Connecting', 'Connected', + 'Unable to connect. Error: [error message]'} + _as_of: + type: string + description: The last time the device was successfully pinged, in ISO 8601 format (yyyy-MM-ddTHH:mm:ss.SSS) + DeviceTags: + description: Information on the tags of a specific device + type: object + required: + - id + - tags + - _as_of + properties: + id: + type: string + description: Globally unique device ID + tags: + type: array + items: + $ref: "#/components/schemas/DeviceTag" + description: The tags on the device + _as_of: + type: string + description: The last time the device was successfully pinged, in ISO 8601 format (yyyy-MM-ddTHH:mm:ss.SSS) + DeviceTag: + description: A tag on a device + type: object + required: + - key + - value + - namespace + properties: + key: + type: string + description: The key of the tag + namespace: + type: string + description: >- + The namespace of the tag. Usually 'psoNamespace' (for PSO-set internal + labels) or 'pure1-unplugged' (for user-set tags) + value: + type: string + description: The value of the tag + ErrorResponse: + description: The response given for an error + type: object + required: + - code + - text + properties: + code: + type: integer + description: The HTTP error code of this error + namespace: + type: string + description: The actual error message that caused this error code diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/NOTES.txt new file mode 100644 index 00000000..e69de29b diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/_helpers.tpl new file mode 100644 index 00000000..23787f71 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "swagger-server.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "swagger-server.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "swagger-server.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/templates/configmap.yaml b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/configmap.yaml new file mode 100644 index 00000000..a5416601 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/configmap.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "swagger-server.fullname" . }}-swagger-file + labels: + app: {{ template "swagger-server.name" . }} + chart: {{ template "swagger-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: +{{ (.Files.Glob "api-server-swagger.yaml").AsConfig | indent 2 }} diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/templates/deployment.yaml b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/deployment.yaml new file mode 100644 index 00000000..623e9d2d --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/deployment.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "swagger-server.fullname" . }} + labels: + app: {{ template "swagger-server.name" . }} + chart: {{ template "swagger-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "swagger-server.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "swagger-server.name" . }} + release: {{ .Release.Name }} + spec: + volumes: + - name: swagger-file + configMap: + name: {{ template "swagger-server.fullname" . }}-swagger-file + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: SWAGGER_JSON + value: /swagger/api-server-swagger.yaml + ports: + - name: http + containerPort: 8080 + protocol: TCP + volumeMounts: + - name: swagger-file + mountPath: /swagger/ + readOnly: true + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/templates/ingress.yaml b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/ingress.yaml new file mode 100644 index 00000000..17f33e05 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "swagger-server.fullname" . -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ template "swagger-server.name" . }} + chart: {{ template "swagger-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /$1 + ingress.kubernetes.io/secure-backends: "false" + nginx.ingress.kubernetes.io/configuration-snippet: | + sub_filter '' ' '; + nginx.ingress.kubernetes.io/auth-url: "https://$host/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/auth/login" +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /swagger/?(.*) + backend: + serviceName: {{ $fullName }} + servicePort: http +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/templates/service.yaml b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/service.yaml new file mode 100644 index 00000000..03649531 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "swagger-server.fullname" . }} + labels: + app: {{ template "swagger-server.name" . }} + chart: {{ template "swagger-server.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "swagger-server.name" . }} + release: {{ .Release.Name }} diff --git a/deploy/helm/pure1-unplugged/charts/swagger-server/values.yaml b/deploy/helm/pure1-unplugged/charts/swagger-server/values.yaml new file mode 100644 index 00000000..67bfdbe9 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/swagger-server/values.yaml @@ -0,0 +1,34 @@ +# Default values for swagger-server. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: swaggerapi/swagger-ui + tag: v3.20.7 + pullPolicy: IfNotPresent + +service: + port: 80 + +ingress: + enabled: true + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/deploy/helm/pure1-unplugged/charts/web-content/.helmignore b/deploy/helm/pure1-unplugged/charts/web-content/.helmignore new file mode 100644 index 00000000..f0c13194 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/.helmignore @@ -0,0 +1,21 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/helm/pure1-unplugged/charts/web-content/Chart.yaml b/deploy/helm/pure1-unplugged/charts/web-content/Chart.yaml new file mode 100644 index 00000000..46d00998 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: A Helm chart for Kubernetes +name: web-content +version: 0.1.0 diff --git a/deploy/helm/pure1-unplugged/charts/web-content/templates/NOTES.txt b/deploy/helm/pure1-unplugged/charts/web-content/templates/NOTES.txt new file mode 100644 index 00000000..e69de29b diff --git a/deploy/helm/pure1-unplugged/charts/web-content/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/charts/web-content/templates/_helpers.tpl new file mode 100644 index 00000000..156eb952 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "web-content.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "web-content.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "web-content.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/charts/web-content/templates/dash-ingress.yaml b/deploy/helm/pure1-unplugged/charts/web-content/templates/dash-ingress.yaml new file mode 100644 index 00000000..544f504b --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/templates/dash-ingress.yaml @@ -0,0 +1,38 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "web-content.fullname" . -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + app: {{ template "web-content.name" . }} + chart: {{ template "web-content.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + kubernetes.io/ingress.class: nginx + ingress.kubernetes.io/secure-backends: "false" + nginx.ingress.kubernetes.io/auth-url: "https://$host/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/auth/login" +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: / + backend: + serviceName: {{ $fullName }} + servicePort: http +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/web-content/templates/deployment.yaml b/deploy/helm/pure1-unplugged/charts/web-content/templates/deployment.yaml new file mode 100644 index 00000000..6e297b05 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/templates/deployment.yaml @@ -0,0 +1,51 @@ +apiVersion: apps/v1beta2 +kind: Deployment +metadata: + name: {{ template "web-content.fullname" . }} + labels: + app: {{ template "web-content.name" . }} + chart: {{ template "web-content.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app: {{ template "web-content.name" . }} + release: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ template "web-content.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.global.pure1unplugged.image.repository }}:{{ .Values.global.pure1unplugged.image.tag }}" + imagePullPolicy: {{ .Values.global.pure1unplugged.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/web-content/templates/login-ingress.yaml b/deploy/helm/pure1-unplugged/charts/web-content/templates/login-ingress.yaml new file mode 100644 index 00000000..5e92fe1b --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/templates/login-ingress.yaml @@ -0,0 +1,38 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "web-content.fullname" . -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: {{ $fullName }}-login + labels: + app: {{ template "web-content.name" . }} + chart: {{ template "web-content.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + kubernetes.io/ingress.class: nginx + ingress.kubernetes.io/secure-backends: "false" + ingress.kubernetes.io/app-root: /login +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /login + backend: + serviceName: {{ $fullName }} + servicePort: http + +{{- end }} diff --git a/deploy/helm/pure1-unplugged/charts/web-content/templates/service.yaml b/deploy/helm/pure1-unplugged/charts/web-content/templates/service.yaml new file mode 100644 index 00000000..defd0b87 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "web-content.fullname" . }} + labels: + app: {{ template "web-content.name" . }} + chart: {{ template "web-content.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + app: {{ template "web-content.name" . }} + release: {{ .Release.Name }} diff --git a/deploy/helm/pure1-unplugged/charts/web-content/values.yaml b/deploy/helm/pure1-unplugged/charts/web-content/values.yaml new file mode 100644 index 00000000..7462ad14 --- /dev/null +++ b/deploy/helm/pure1-unplugged/charts/web-content/values.yaml @@ -0,0 +1,29 @@ +# Default values for web-content. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +service: + port: 80 + +ingress: + enabled: true + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/deploy/helm/pure1-unplugged/requirements.lock b/deploy/helm/pure1-unplugged/requirements.lock new file mode 100644 index 00000000..edd5ec15 --- /dev/null +++ b/deploy/helm/pure1-unplugged/requirements.lock @@ -0,0 +1,12 @@ +dependencies: +- name: elasticsearch + repository: https://kubernetes-charts.storage.googleapis.com + version: 1.17.0 +- name: kibana + repository: https://kubernetes-charts.storage.googleapis.com + version: 1.1.2 +- name: nginx-ingress + repository: https://kubernetes-charts.storage.googleapis.com + version: 1.3.1 +digest: sha256:a76dcc2c56d08b0e6deb4b2fe731cefad2cac40433f2b7127a645e2cd02df9dd +generated: 2019-03-08T11:57:11.117498304-08:00 diff --git a/deploy/helm/pure1-unplugged/requirements.yaml b/deploy/helm/pure1-unplugged/requirements.yaml new file mode 100644 index 00000000..045e7f91 --- /dev/null +++ b/deploy/helm/pure1-unplugged/requirements.yaml @@ -0,0 +1,10 @@ +dependencies: +- name: elasticsearch + version: 1.17.0 + repository: https://kubernetes-charts.storage.googleapis.com +- name: kibana + version: 1.1.2 + repository: https://kubernetes-charts.storage.googleapis.com +- name: nginx-ingress + version: 1.3.1 + repository: "@stable" diff --git a/deploy/helm/pure1-unplugged/templates/_helpers.tpl b/deploy/helm/pure1-unplugged/templates/_helpers.tpl new file mode 100644 index 00000000..dc1017a3 --- /dev/null +++ b/deploy/helm/pure1-unplugged/templates/_helpers.tpl @@ -0,0 +1,8 @@ +{{/* +Get the FQDN from the global.publicAddress value. If its an IP address set "" +*/}} +{{- define "publicAddress.domainName" -}} +{{- if not (regexMatch "^(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$" .Values.global.publicAddress) -}} +{{- .Values.global.publicAddress -}} +{{- end -}} +{{- end -}} diff --git a/deploy/helm/pure1-unplugged/templates/elasticsearch-ingress.yaml b/deploy/helm/pure1-unplugged/templates/elasticsearch-ingress.yaml new file mode 100644 index 00000000..890dd28a --- /dev/null +++ b/deploy/helm/pure1-unplugged/templates/elasticsearch-ingress.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + labels: + app: {{ template "elasticsearch.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + name: {{ template "elasticsearch.fullname" . }}-elasticsearch + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /$1 + ingress.kubernetes.io/secure-backends: "false" + nginx.ingress.kubernetes.io/auth-url: "https://$host/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/auth/login" +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /elasticsearch/?(.*) + backend: + serviceName: pure1-unplugged-elasticsearch-client + servicePort: 9200 + +{{ end }} diff --git a/deploy/helm/pure1-unplugged/templates/kibana-ingress.yaml b/deploy/helm/pure1-unplugged/templates/kibana-ingress.yaml new file mode 100644 index 00000000..dcdf363d --- /dev/null +++ b/deploy/helm/pure1-unplugged/templates/kibana-ingress.yaml @@ -0,0 +1,38 @@ +{{- if .Values.ingress.enabled -}} +{{- $domainName := include "publicAddress.domainName" . -}} +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + labels: + app: {{ template "kibana.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + name: {{ template "kibana.fullname" . }}-kibana + annotations: + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/rewrite-target: /$1 + ingress.kubernetes.io/secure-backends: "false" + nginx.ingress.kubernetes.io/auth-url: "https://$host/auth" + nginx.ingress.kubernetes.io/auth-signin: "https://$host/auth/login" +spec: + tls: + - secretName: {{ .Values.global.httpsCertSecret }} + {{- if $domainName }} + hosts: + - {{ $domainName }} + {{- end }} + + rules: + - http: + {{- if $domainName }} + host: {{ $domainName }} + {{ else }} + # host: ## Not specified because global.PublicAddress is an IP address + {{ end -}} + paths: + - path: /kibana/?(.*) + backend: + serviceName: pure1-unplugged-kibana + servicePort: 443 +{{ end }} diff --git a/deploy/helm/pure1-unplugged/values.yaml b/deploy/helm/pure1-unplugged/values.yaml new file mode 100644 index 00000000..932cef58 --- /dev/null +++ b/deploy/helm/pure1-unplugged/values.yaml @@ -0,0 +1,144 @@ +# Define global variables here, this is a reserved keyword! +global: + # publicAddress is the public FQDN or IP address where pure1-unplugged will be reached. + # it is highly recommended to use an FQDN in case the IP address shifts over time. + publicAddress: pure1-unplugged.example.com + httpsCertSecret: pure1-unplugged-https-cert + + pure1unplugged: + # Use this to specify how long to keep metrics for devices and volumes, in days. Defaults + # to 31 days/1 month + metricRetentionPeriod: 31 + + # Use this to specify how long alerts should be kept before they are discarded, in days. Defaults to 365 days + alertRetentionPeriod: 365 + + # Use this to specify how long to keep error/warning log lines before they are discarded, in days. Defaults to 1 day + errorLogRetentionPeriod: 1 + + # Use this to specify how long to keep timer logs before they are discarded, in days. Defaults to 1 day. + # Highly recommended to keep this value low as this is a very large amount of data. + timerLogRetentionPeriod: 1 + + # Use this to specify how often FlashArray volume metrics information should be collected, in seconds. Defaults to 30 seconds. + faVolumeCollectionPeriod: 30 + + # Use this to specify how often FlashArray volume (filesystem) metrics information should be collected, in seconds. Defaults to 300 seconds. + # Note that anything less than 300 seconds may have performance concerns for the FlashBlade and Pure1 Unplugged. + fbVolumeCollectionPeriod: 300 + + image: + repository: purestorage/pure1-unplugged + # Tag needs to be either overwritten by a caller, or swapped with the real one at "build" time + # of the pure1-unplugged install bundle + tag: @PURE1_UNPLUGGED_VERSION@ + pullPolicy: IfNotPresent + +dex: + tokenTTL: 30m + enablePasswordDBConnector: true + staticPasswords: + - email: "admin@example.com" + # bcrypt hash of the string "password" + hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" + username: "admin" + userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" + + connectors: + - type: ldap + id: ldap + name: LDAP + config: + host: ldap.forumsys.com:389 + insecureNoSSL: true # NOTE: this is subject to removal at any point as this is intrinsically very VERY insecure! + insecureSkipVerify: true + bindDN: cn=read-only-admin,dc=example,dc=com + bindPW: password + usernamePrompt: SSO Username + userSearch: + baseDN: dc=example,dc=com + filter: "(objectClass=person)" + username: uid + idAttr: uid + emailAttr: mail + nameAttr: cn + groupSearch: + baseDN: dc=example,dc=com + filter: "(objectClass=groupOfUniqueNames)" + userAttr: uid + groupAttr: uniqueMember + nameAttr: cn + # Example Github connector + #- type: github + # id: github + # name: GitHub + # config: + # clientID: $GITHUB_CLIENT_ID + # clientSecret: $GITHUB_CLIENT_SECRET + # redirectURI: https://{{ .Values.global.publicAddress }}/dex/callback + # org: kubernetes + # oauth2: + # skipApprovalScreen: true + - type: mockCallback + id: mock + name: Example + +elasticsearch: + image: + pullPolicy: IfNotPresent + initImage: + pullPolicy: IfNotPresent + cluster: + env: + MINIMUM_MASTER_NODES: "1" + EXPECTED_MASTER_NODES: "1" + RECOVER_AFTER_MASTER_NODES: "1" + EXPECTED_DATA_NODES: "1" + master: + replicas: 1 + persistence: + size: "2Gi" + storageClass: "elastic-master-pv" + resources: + requests: + memory: "512Mi" + client: + replicas: 1 + serviceType: ClusterIP + resources: + requests: + memory: "1024Mi" + data: + replicas: 1 + persistence: + size: "8Gi" + storageClass: "elastic-data-pv" + resources: + requests: + memory: "2048Mi" + +kibana: + service: + type: ClusterIP + clusterIP: none + env: + ELASTICSEARCH_URL: "http://pure1-unplugged-elasticsearch-client:9200" + SERVER_HOST: "0.0.0.0" + SERVER_BASEPATH: "/kibana" + # NOTE: this used to be true when we were on Elasticsearch 6.3.1. Good lesson that upgrading helm charts can break ingress rules. + # Leaving this here (but set to the proper value) as a reminder that it can be changed and in case this bug/feature re-manifests later. + SERVER_REWRITEBASEPATH: false + LOGGING_VERBOSE: "true" + +nginx-ingress: + controller: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + service: + type: NodePort + extraArgs: + default-ssl-certificate: pure1-unplugged-https-cert + v: 3 + +ingress: + enabled: true diff --git a/deploy/infra/calico/calico.yaml.template b/deploy/infra/calico/calico.yaml.template new file mode 100644 index 00000000..84b53be3 --- /dev/null +++ b/deploy/infra/calico/calico.yaml.template @@ -0,0 +1,508 @@ +# Calico Version v3.5.2 +# https://docs.projectcalico.org/v3.5/releases#v3.5.2 +# This manifest includes the following component versions: +# calico/node:v3.5.2 +# calico/cni:v3.5.2 + +# This ConfigMap is used to configure a self-hosted Calico installation. +kind: ConfigMap +apiVersion: v1 +metadata: + name: calico-config + namespace: kube-system +data: + # Typha is disabled. + typha_service_name: "none" + # Configure the Calico backend to use. + calico_backend: "bird" + + # Configure the MTU to use + veth_mtu: "1440" + + # The CNI network configuration to install on each node. The special + # values in this config will be automatically populated. + cni_network_config: |- + { + "name": "k8s-pod-network", + "cniVersion": "0.3.0", + "plugins": [ + { + "type": "calico", + "log_level": "info", + "datastore_type": "kubernetes", + "nodename": "__KUBERNETES_NODE_NAME__", + "mtu": __CNI_MTU__, + "ipam": { + "type": "host-local", + "subnet": "usePodCidr" + }, + "policy": { + "type": "k8s" + }, + "kubernetes": { + "kubeconfig": "__KUBECONFIG_FILEPATH__" + } + }, + { + "type": "portmap", + "snat": true, + "capabilities": {"portMappings": true} + } + ] + } + +--- + +# This manifest installs the calico/node container, as well +# as the Calico CNI plugins and network config on +# each master and worker node in a Kubernetes cluster. +kind: DaemonSet +apiVersion: extensions/v1beta1 +metadata: + name: calico-node + namespace: kube-system + labels: + k8s-app: calico-node +spec: + selector: + matchLabels: + k8s-app: calico-node + updateStrategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + template: + metadata: + labels: + k8s-app: calico-node + annotations: + # This, along with the CriticalAddonsOnly toleration below, + # marks the pod as a critical add-on, ensuring it gets + # priority scheduling and that its resources are reserved + # if it ever gets evicted. + scheduler.alpha.kubernetes.io/critical-pod: '' + spec: + nodeSelector: + beta.kubernetes.io/os: linux + hostNetwork: true + tolerations: + # Make sure calico-node gets scheduled on all nodes. + - effect: NoSchedule + operator: Exists + # Mark the pod as a critical add-on for rescheduling. + - key: CriticalAddonsOnly + operator: Exists + - effect: NoExecute + operator: Exists + serviceAccountName: calico-node + # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a "force + # deletion": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods. + terminationGracePeriodSeconds: 0 + initContainers: + # This container installs the Calico CNI binaries + # and CNI network config file on each node. + - name: install-cni + image: calico/cni:v3.5.2 + command: ["/install-cni.sh"] + env: + # Name of the CNI config file to create. + - name: CNI_CONF_NAME + value: "10-calico.conflist" + # The CNI network config to install on each node. + - name: CNI_NETWORK_CONFIG + valueFrom: + configMapKeyRef: + name: calico-config + key: cni_network_config + # Set the hostname based on the k8s node name. + - name: KUBERNETES_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # CNI MTU Config variable + - name: CNI_MTU + valueFrom: + configMapKeyRef: + name: calico-config + key: veth_mtu + # Prevents the container from sleeping forever. + - name: SLEEP + value: "false" + volumeMounts: + - mountPath: /host/opt/cni/bin + name: cni-bin-dir + - mountPath: /host/etc/cni/net.d + name: cni-net-dir + containers: + # Runs calico/node container on each Kubernetes node. This + # container programs network policy and routes on each + # host. + - name: calico-node + image: calico/node:v3.5.2 + env: + # Use Kubernetes API as the backing datastore. + - name: DATASTORE_TYPE + value: "kubernetes" + # Wait for the datastore. + - name: WAIT_FOR_DATASTORE + value: "true" + # Set based on the k8s node name. + - name: NODENAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + # Choose the backend to use. + - name: CALICO_NETWORKING_BACKEND + valueFrom: + configMapKeyRef: + name: calico-config + key: calico_backend + # Cluster type to identify the deployment type + - name: CLUSTER_TYPE + value: "k8s,bgp" + # Auto-detect the BGP IP address. + - name: IP + value: "autodetect" + # Enable IPIP + - name: CALICO_IPV4POOL_IPIP + value: "Always" + # Set MTU for tunnel device used if ipip is enabled + - name: FELIX_IPINIPMTU + valueFrom: + configMapKeyRef: + name: calico-config + key: veth_mtu + # The default IPv4 pool to create on startup if none exists. Pod IPs will be + # chosen from this range. Changing this value after installation will have + # no effect. This should fall within `--cluster-cidr`. + - name: CALICO_IPV4POOL_CIDR + value: "{{ .CalicoPodCIDR }}" + # Disable file logging so `kubectl logs` works. + - name: CALICO_DISABLE_FILE_LOGGING + value: "true" + # Set Felix endpoint to host default action to ACCEPT. + - name: FELIX_DEFAULTENDPOINTTOHOSTACTION + value: "ACCEPT" + # Disable IPv6 on Kubernetes. + - name: FELIX_IPV6SUPPORT + value: "false" + # Set Felix logging to "info" + - name: FELIX_LOGSEVERITYSCREEN + value: "info" + - name: FELIX_HEALTHENABLED + value: "true" + securityContext: + privileged: true + resources: + requests: + cpu: 250m + livenessProbe: + httpGet: + path: /liveness + port: 9099 + host: localhost + periodSeconds: 10 + initialDelaySeconds: 10 + failureThreshold: 6 + readinessProbe: + exec: + command: + - /bin/calico-node + - -bird-ready + - -felix-ready + periodSeconds: 10 + volumeMounts: + - mountPath: /lib/modules + name: lib-modules + readOnly: true + - mountPath: /run/xtables.lock + name: xtables-lock + readOnly: false + - mountPath: /var/run/calico + name: var-run-calico + readOnly: false + - mountPath: /var/lib/calico + name: var-lib-calico + readOnly: false + volumes: + # Used by calico/node. + - name: lib-modules + hostPath: + path: /lib/modules + - name: var-run-calico + hostPath: + path: /var/run/calico + - name: var-lib-calico + hostPath: + path: /var/lib/calico + - name: xtables-lock + hostPath: + path: /run/xtables.lock + type: FileOrCreate + # Used to install CNI. + - name: cni-bin-dir + hostPath: + path: /opt/cni/bin + - name: cni-net-dir + hostPath: + path: /etc/cni/net.d +--- + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: calico-node + namespace: kube-system + +--- +# Create all the CustomResourceDefinitions needed for +# Calico policy and networking mode. + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: felixconfigurations.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: FelixConfiguration + plural: felixconfigurations + singular: felixconfiguration +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: bgppeers.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: BGPPeer + plural: bgppeers + singular: bgppeer + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: bgpconfigurations.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: BGPConfiguration + plural: bgpconfigurations + singular: bgpconfiguration + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: ippools.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: IPPool + plural: ippools + singular: ippool + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: hostendpoints.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: HostEndpoint + plural: hostendpoints + singular: hostendpoint + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusterinformations.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: ClusterInformation + plural: clusterinformations + singular: clusterinformation + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: globalnetworkpolicies.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: GlobalNetworkPolicy + plural: globalnetworkpolicies + singular: globalnetworkpolicy + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: globalnetworksets.crd.projectcalico.org +spec: + scope: Cluster + group: crd.projectcalico.org + version: v1 + names: + kind: GlobalNetworkSet + plural: globalnetworksets + singular: globalnetworkset + +--- + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: networkpolicies.crd.projectcalico.org +spec: + scope: Namespaced + group: crd.projectcalico.org + version: v1 + names: + kind: NetworkPolicy + plural: networkpolicies + singular: networkpolicy +--- + +# Include a clusterrole for the calico-node DaemonSet, +# and bind it to the calico-node serviceaccount. +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: calico-node +rules: + # The CNI plugin needs to get pods, nodes, and namespaces. + - apiGroups: [""] + resources: + - pods + - nodes + - namespaces + verbs: + - get + - apiGroups: [""] + resources: + - endpoints + - services + verbs: + # Used to discover service IPs for advertisement. + - watch + - list + # Used to discover Typhas. + - get + - apiGroups: [""] + resources: + - nodes/status + verbs: + # Needed for clearing NodeNetworkUnavailable flag. + - patch + # Calico stores some configuration information in node annotations. + - update + # Watch for changes to Kubernetes NetworkPolicies. + - apiGroups: ["networking.k8s.io"] + resources: + - networkpolicies + verbs: + - watch + - list + # Used by Calico for policy information. + - apiGroups: [""] + resources: + - pods + - namespaces + - serviceaccounts + verbs: + - list + - watch + # The CNI plugin patches pods/status. + - apiGroups: [""] + resources: + - pods/status + verbs: + - patch + # Calico monitors various CRDs for config. + - apiGroups: ["crd.projectcalico.org"] + resources: + - globalfelixconfigs + - felixconfigurations + - bgppeers + - globalbgpconfigs + - bgpconfigurations + - ippools + - globalnetworkpolicies + - globalnetworksets + - networkpolicies + - clusterinformations + - hostendpoints + verbs: + - get + - list + - watch + # Calico must create and update some CRDs on startup. + - apiGroups: ["crd.projectcalico.org"] + resources: + - ippools + - felixconfigurations + - clusterinformations + verbs: + - create + - update + # Calico stores some configuration information on the node. + - apiGroups: [""] + resources: + - nodes + verbs: + - get + - list + - watch + # These permissions are only requried for upgrade from v2.6, and can + # be removed after upgrade or on fresh installations. + - apiGroups: ["crd.projectcalico.org"] + resources: + - bgpconfigurations + - bgppeers + verbs: + - create + - update +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: calico-node +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: calico-node +subjects: +- kind: ServiceAccount + name: calico-node + namespace: kube-system +--- + + diff --git a/deploy/infra/calico/calicoctl.yaml.template b/deploy/infra/calico/calicoctl.yaml.template new file mode 100644 index 00000000..3caadbb9 --- /dev/null +++ b/deploy/infra/calico/calicoctl.yaml.template @@ -0,0 +1,91 @@ +# Calico Version v3.5.2 +# https://docs.projectcalico.org/v3.5/releases#v3.5.2 +# This manifest includes the following component versions: +# calico/ctl:v3.5.2 + +apiVersion: v1 +kind: ServiceAccount +metadata: + name: calicoctl + namespace: kube-system + +--- + +apiVersion: v1 +kind: Pod +metadata: + name: calicoctl + namespace: kube-system +spec: + nodeSelector: + beta.kubernetes.io/os: linux + hostNetwork: true + serviceAccountName: calicoctl + containers: + - name: calicoctl + image: calico/ctl:v3.5.2 + command: ["/bin/sh", "-c", "while true; do sleep 3600; done"] + env: + - name: DATASTORE_TYPE + value: kubernetes + +--- + +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: calicoctl +rules: + - apiGroups: [""] + resources: + - namespaces + - nodes + verbs: + - get + - list + - update + - apiGroups: [""] + resources: + - pods + - serviceaccounts + verbs: + - get + - list + - apiGroups: [""] + resources: + - pods/status + verbs: + - update + - apiGroups: ["crd.projectcalico.org"] + resources: + - bgppeers + - bgpconfigurations + - clusterinformations + - felixconfigurations + - globalnetworkpolicies + - globalnetworksets + - ippools + - networkpolicies + - hostendpoints + verbs: + - create + - get + - list + - update + - delete + +--- + +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: calicoctl +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: calicoctl +subjects: +- kind: ServiceAccount + name: calicoctl + namespace: kube-system + diff --git a/deploy/infra/helm/helm-v2.13.0 b/deploy/infra/helm/helm-v2.13.0 new file mode 100755 index 00000000..0ebddea1 Binary files /dev/null and b/deploy/infra/helm/helm-v2.13.0 differ diff --git a/deploy/infra/helm/tiller-rbac.yaml b/deploy/infra/helm/tiller-rbac.yaml new file mode 100644 index 00000000..5309e8be --- /dev/null +++ b/deploy/infra/helm/tiller-rbac.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tiller + namespace: kube-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: tiller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: +- kind: ServiceAccount + name: tiller + namespace: kube-system diff --git a/deploy/infra/kubeadm/kube-api-encryption.yaml.template b/deploy/infra/kubeadm/kube-api-encryption.yaml.template new file mode 100644 index 00000000..88df998c --- /dev/null +++ b/deploy/infra/kubeadm/kube-api-encryption.yaml.template @@ -0,0 +1,19 @@ +kind: EncryptionConfiguration +apiVersion: apiserver.config.k8s.io/v1 +resources: + - resources: + - secrets + - authcodes.dex.coreos.com + - authrequests.dex.coreos.com + - connectors.dex.coreos.com + - oauth2clients.dex.coreos.com + - offlinesessionses.dex.coreos.com + - passwords.dex.coreos.com + - refreshtokens.dex.coreos.com + - signingkeies.dex.coreos.com + providers: + - aescbc: + keys: + - name: key1 + secret: "{{ .EncryptionKey }}" + - identity: {} diff --git a/deploy/infra/kubeadm/kubeadm-init-config.yaml.template b/deploy/infra/kubeadm/kubeadm-init-config.yaml.template new file mode 100644 index 00000000..632b9de3 --- /dev/null +++ b/deploy/infra/kubeadm/kubeadm-init-config.yaml.template @@ -0,0 +1,46 @@ +apiVersion: kubeadm.k8s.io/v1beta1 +kind: InitConfiguration +bootstrapTokens: + - groups: + - system:bootstrappers:kubeadm:default-node-token + token: {{ .Token }} + ttl: 24h0m0s + usages: + - signing + - authentication +localAPIEndpoint: + advertiseAddress: 0.0.0.0 + bindPort: 6443 +nodeRegistration: + criSocket: /var/run/dockershim.sock + name: {{ .NodeName }} + taints: + - effect: NoSchedule + key: node-role.kubernetes.io/master +--- +apiVersion: kubeadm.k8s.io/v1beta1 +kind: ClusterConfiguration +apiServer: + timeoutForControlPlane: 4m0s + extraArgs: + encryption-provider-config: /etc/kubernetes/secrets/kube-api-encryption.yaml + extraVolumes: + - name: secrets + hostPath: /etc/kubernetes/secrets + mountPath: /etc/kubernetes/secrets +certificatesDir: /etc/kubernetes/pki +clusterName: Kubernetes +controlPlaneEndpoint: "" +controllerManager: {} +dns: + type: CoreDNS +etcd: + local: + dataDir: /var/lib/etcd +imageRepository: k8s.gcr.io +kubernetesVersion: {{ .KubernetesVersion }} +networking: + dnsDomain: cluster.local + podSubnet: {{ .PodCIDR }} + serviceSubnet: {{ .ServiceCIDR }} +scheduler: {} diff --git a/deploy/infra/playbooks/infra-prereq.yaml b/deploy/infra/playbooks/infra-prereq.yaml new file mode 100644 index 00000000..68faf071 --- /dev/null +++ b/deploy/infra/playbooks/infra-prereq.yaml @@ -0,0 +1,165 @@ +- name: pure1-unplugged infra setup + hosts: all + tasks: + ##### Selinux config ##### + - name: selinux config + selinux: + policy: targeted + state: enforcing + + ##### Network config ##### + - name: enable br_netfilter kernel module + modprobe: + name: br_netfilter + state: present + + - name: set ipv6 bridge-nfs-call-ip6tables + sysctl: + name: net.bridge.bridge-nf-call-ip6tables + value: 1 + state: present + sysctl_set: yes + reload: yes + + - name: set ipv4 bridge-nfs-call-iptables + sysctl: + name: net.bridge.bridge-nf-call-iptables + value: 1 + state: present + sysctl_set: yes + reload: yes + + - name: get long hostname + shell: hostname --long + register: full_hostname_shell_output + + - set_fact: + full_hostname: "{{ full_hostname_shell_output.stdout }}" + + - name: get short hostname + shell: hostname --short + register: short_hostname_shell_output + + - set_fact: + short_hostname: "{{ short_hostname_shell_output.stdout }}" + + - name: add hostname to /etc/hosts + lineinfile: + dest=/etc/hosts + line='127.0.0.1 localhost localhost.localdomain {{ full_hostname }} {{ short_hostname }}' + regexp='^127\.0\.0\.1' + insertafter='^127\.0\.0\.1' + state=present + + ##### Firewall config ##### + - name: enable firewalld service + shell: systemctl enable firewalld + + - name: reload firewalld service + shell: systemctl daemon-reload + + - name: start firewalld + systemd: + name: firewalld + enabled: true + state: started + + - name: enable https service with firewall + firewalld: + service: https + permanent: yes + immediate: yes + state: enabled + + - name: enable ssh service with firewall + firewalld: + service: ssh + permanent: yes + immediate: yes + state: enabled + + ##### Swap config ##### + - name: Remove swapfile from /etc/fstab + mount: + name: swap + fstype: swap + state: absent + + - name: Disable swap + command: swapoff -a + when: ansible_swaptotal_mb > 0 + + ##### Docker config ##### + - name: ensure /etc/docker exists + file: + path: /etc/docker + state: directory + mode: 0755 + + - name: update /etc/docker/daemon.json + template: + src: templates/docker-daemon.json.j2 + dest: /etc/docker/daemon.json + + - name: ensure docker service directory exists + file: + path: /etc/systemd/system/docker.service.d + state: directory + mode: 0755 + + - name: enable docker service + shell: systemctl enable docker + + - name: reload docker service + shell: systemctl daemon-reload + + - name: bounce the docker service to ensure it has correct daemon.json + systemd: + name: docker + enabled: true + state: restarted + + ##### Kubelet config ##### + + # Don't start the kubelet service yet, it will only go into an error state until `kubeadm init` + # just make sure it is enabled and loaded + + - name: enable kubelet service + shell: systemctl enable kubelet + + - name: reload kubelet service + shell: systemctl daemon-reload + + ##### helm ##### + - name: install helm bin + copy: + src: /opt/pure1-unplugged/infra/helm/helm + dest: /usr/bin/helm + owner: root + group: root + mode: preserve + + ##### Yum Repos ##### + - name: clear existing repos + file: + path: /etc/yum.repos.d/ + state: "{{ item }}" + with_items: + - absent + - directory + + - name: install disabled centos base repo + template: + src: templates/CentOS-Base.repo.j2 + dest: /etc/yum.repos.d/CentOS-Base.repo + + - name: install pure1-unplugged media repo + template: + src: templates/Pure1-Unplugged-Media.repo.j2 + dest: /etc/yum.repos.d/Pure1-Unplugged-Media.repo + + ##### udev rules ##### + - name: install pure1-unplugged iso udev rule + template: + src: templates/90-pure1-unplugged-media-by-label-auto-mount.rules + dest: /etc/udev/rules.d/90-pure1-unplugged-media-by-label-auto-mount.rules diff --git a/deploy/infra/playbooks/templates/90-pure1-unplugged-media-by-label-auto-mount.rules b/deploy/infra/playbooks/templates/90-pure1-unplugged-media-by-label-auto-mount.rules new file mode 100644 index 00000000..ae311266 --- /dev/null +++ b/deploy/infra/playbooks/templates/90-pure1-unplugged-media-by-label-auto-mount.rules @@ -0,0 +1,23 @@ +# Only look at block devices (it could be a scsi disk, cdrom, ide disk, etc.. lets support them all +SUBSYSTEM!="block", GOTO="pure1_unplugged_media_by_label_auto_mount_end" + +# Import FS env info so we can look at the label +IMPORT{program}="/sbin/blkid -o udev -p %N" + +# Get a label if present, if it matches our iso filesystem label continue onwards otherwise exit +ENV{ID_FS_LABEL}!="Pure1-UNPLUGGED_x86_64", GOTO="pure1_unplugged_media_by_label_auto_mount_end" + +# Add some environment variables for our device +ACTION=="add|change", ENV{mount_dir}="%E{ID_FS_LABEL}" + +# Mount the device (add/remove workflow, if the iso is on a loopback device or something) +ACTION=="add", RUN+="/bin/mkdir -p /media/%E{mount_dir}", RUN+="/bin/mount /dev/%k /media/%E{mount_dir}" RUN+="/bin/sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/Pure1 Unplugged-Media.repo" +ACTION=="remove", RUN+="/bin/umount /media/%E{mount_dir}", RUN+="/bin/rmdir /dev/%k" RUN+="/bin/sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/Pure1 Unplugged-Media.repo" + +# Mount the device (change workflow, cdroms will behave like this for the most part) +# when ID_CDROM_MEDIA == 1 it means some media is in the drive) +ACTION=="change", ENV{ID_CDROM_MEDIA}=="1", RUN+="/bin/mkdir -p /media/%E{mount_dir}", RUN+="/bin/mount /dev/%k /media/%E{mount_dir}" RUN+="/bin/sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/Pure1 Unplugged-Media.repo" +ACTION=="change", ENV{ID_CDROM_MEDIA}=="", RUN+="/bin/umount -l /dev/%k", RUN+="/bin/rmdir /media/%E{mount_dir}" RUN+="/bin/sed -i 's/enabled=1/enabled=0/g' /etc/yum.repos.d/Pure1 Unplugged-Media.repo" + +# Exit +LABEL="pure1_unplugged_media_by_label_auto_mount_end" diff --git a/deploy/infra/playbooks/templates/CentOS-Base.repo.j2 b/deploy/infra/playbooks/templates/CentOS-Base.repo.j2 new file mode 100644 index 00000000..915cca44 --- /dev/null +++ b/deploy/infra/playbooks/templates/CentOS-Base.repo.j2 @@ -0,0 +1,46 @@ +# CentOS-Base.repo +# +# The mirror system uses the connecting IP address of the client and the +# update status of each mirror to pick mirrors that are updated to and +# geographically close to the client. You should use this for CentOS updates +# unless you are manually picking other mirrors. +# +# If the mirrorlist= does not work for you, as a fall back you can try the +# remarked out baseurl= line instead. +# +# + +[base] +name=CentOS-$releasever - Base +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#released updates +[updates] +name=CentOS-$releasever - Updates +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#additional packages that may be useful +[extras] +name=CentOS-$releasever - Extras +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/extras/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 + +#additional packages that extend functionality of existing packages +[centosplus] +name=CentOS-$releasever - Plus +mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra +#baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/ +gpgcheck=1 +enabled=0 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 diff --git a/deploy/infra/playbooks/templates/Pure1-Unplugged-Media.repo.j2 b/deploy/infra/playbooks/templates/Pure1-Unplugged-Media.repo.j2 new file mode 100644 index 00000000..d7d6ed4e --- /dev/null +++ b/deploy/infra/playbooks/templates/Pure1-Unplugged-Media.repo.j2 @@ -0,0 +1,20 @@ +# Pure1-Unplugged-Media.repo +# +# This repo can be used with mounted DVD media, verify the mount point for +# CentOS-7. You can use this repo and yum to install items directly off the +# DVD ISO that we release. +# +# To use this repo, put in your DVD and use it with the other repos too: +# yum --enablerepo=pure1-unplugged-media [command] +# +# or for ONLY the media repo, do this: +# +# yum --disablerepo=\* --enablerepo=pure1-unplugged-media [command] + +[pure1-unplugged-media] +name=Pure1 Unplugged - Media +baseurl=file:///media/Pure1-Unplugged_x86_64/ +file:///media/cdrom/ +file:///media/cdrecorder/ +gpgcheck=0 +enabled=0 diff --git a/deploy/infra/playbooks/templates/docker-daemon.json.j2 b/deploy/infra/playbooks/templates/docker-daemon.json.j2 new file mode 100644 index 00000000..4a9da481 --- /dev/null +++ b/deploy/infra/playbooks/templates/docker-daemon.json.j2 @@ -0,0 +1,11 @@ +{ + "exec-opts": ["native.cgroupdriver=cgroupfs"], + "log-driver": "json-file", + "log-opts": { + "max-size": "100m" + }, + "storage-driver": "overlay2", + "storage-opts": [ + "overlay2.override_kernel_check=true" + ] +} diff --git a/gui/.editorconfig b/gui/.editorconfig new file mode 100644 index 00000000..6e87a003 --- /dev/null +++ b/gui/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +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/gui/README.md b/gui/README.md new file mode 100644 index 00000000..4f3355cc --- /dev/null +++ b/gui/README.md @@ -0,0 +1,28 @@ +# GUI +The GUI for Pure1 Unplugged powered by Angular. + +## Building and testing +The `make` commands from the parent directory should be used to lint, build, and test the web content. +``` +make lint-web-content +make web-content +make test-web-content +``` +Additionally, `make web` will rebuild dependencies and do all of the above tasks as well. + +## Modules +There are six modules used. + +* `app-routing`: handles all of the routing for the app +* `core`: houses components that are used dispersed throughout the app, including the sidebar and "main page" / navbar +* `dashboard`: houses components not powered by any services, but that embed Kibana dashboards +* `device`: for the appliances page that displays card views and latest metrics +* `device-alert`: for the messages page that displays alerts +* `support`: for the support page that displays error and timer logs + +## Shared resources +These resources (interfaces, models, and services) are not coupled to one individual module and similar resources should be stored together. The `mocks` are also to be used for all component and service tests. + +## Making changes +All new features and bug fixes should be accompanied with new test cases. +Changes should be accompanied with a screenshot and will be linted and tested. diff --git a/gui/angular.json b/gui/angular.json new file mode 100644 index 00000000..24f440ff --- /dev/null +++ b/gui/angular.json @@ -0,0 +1,139 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "gui": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "app", + "schematics": {}, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "baseHref": "/", + "deployUrl": "/", + "outputPath": "dist/gui", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/styles.scss" + ], + "scripts": [] + }, + "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": true + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "gui:build" + }, + "configurations": { + "production": { + "browserTarget": "gui:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "gui:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.scss" + ], + "scripts": [], + "assets": [ + "src/favicon.ico", + "src/assets" + ] + }, + "configurations": { + "testing": {} + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "gui-e2e": { + "root": "e2e/", + "projectType": "application", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "gui:serve" + }, + "configurations": { + "production": { + "devServerTarget": "gui:serve:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "defaultProject": "gui", + "schematics": { + "@schematics/angular:component": { + "styleext": "scss" + } + } +} + + diff --git a/gui/package-lock.json b/gui/package-lock.json new file mode 100644 index 00000000..22bdaf5a --- /dev/null +++ b/gui/package-lock.json @@ -0,0 +1,11205 @@ +{ + "name": "gui", + "version": "0.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.6.8.tgz", + "integrity": "sha512-ZKTm/zC61iY9IBHOEAKoMSzZpvhkmv+1O/HHzpHEuR551jCzu6vSyCmMY9Z7GBcccscCV+hjeSMwgFrFRcqlkw==", + "dev": true, + "requires": { + "@angular-devkit/core": "0.6.8", + "rxjs": "^6.0.0" + } + }, + "@angular-devkit/build-angular": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.6.8.tgz", + "integrity": "sha512-VGqYAk8jpISraz2UHfsDre270NOUmV0CTSZw2p9sm5g/XIr5m+IHetFZz3gpoAr9+If2aFTs8Rt3sGdCRzwBqA==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.6.8", + "@angular-devkit/build-optimizer": "0.6.8", + "@angular-devkit/core": "0.6.8", + "@ngtools/webpack": "6.0.8", + "ajv": "~6.4.0", + "autoprefixer": "^8.4.1", + "cache-loader": "^1.2.2", + "chalk": "~2.2.2", + "circular-dependency-plugin": "^5.0.2", + "clean-css": "^4.1.11", + "copy-webpack-plugin": "^4.5.1", + "file-loader": "^1.1.11", + "glob": "^7.0.3", + "html-webpack-plugin": "^3.0.6", + "istanbul": "^0.4.5", + "istanbul-instrumenter-loader": "^3.0.1", + "karma-source-map-support": "^1.2.0", + "less": "^3.0.4", + "less-loader": "^4.1.0", + "license-webpack-plugin": "^1.3.1", + "lodash": "^4.17.4", + "memory-fs": "^0.4.1", + "mini-css-extract-plugin": "~0.4.0", + "minimatch": "^3.0.4", + "node-sass": "^4.9.0", + "opn": "^5.1.0", + "parse5": "^4.0.0", + "portfinder": "^1.0.13", + "postcss": "^6.0.22", + "postcss-import": "^11.1.0", + "postcss-loader": "^2.1.5", + "postcss-url": "^7.3.2", + "raw-loader": "^0.5.1", + "resolve": "^1.5.0", + "rxjs": "^6.0.0", + "sass-loader": "^7.0.1", + "silent-error": "^1.1.0", + "source-map-support": "^0.5.0", + "stats-webpack-plugin": "^0.6.2", + "style-loader": "^0.21.0", + "stylus": "^0.54.5", + "stylus-loader": "^3.0.2", + "tree-kill": "^1.2.0", + "uglifyjs-webpack-plugin": "^1.2.5", + "url-loader": "^1.0.1", + "webpack": "~4.8.1", + "webpack-dev-middleware": "^3.1.3", + "webpack-dev-server": "^3.1.4", + "webpack-merge": "^4.1.2", + "webpack-sources": "^1.1.0", + "webpack-subresource-integrity": "^1.1.0-rc.4" + } + }, + "@angular-devkit/build-optimizer": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.6.8.tgz", + "integrity": "sha512-of5syQbv3uNPp4AQkfRecfnp8AE8kvffbfYi+FFPZ6OGr7e59T1fGwk6+Zgb2qQFQg8HO2tzWI/uygtLIqmbmw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "source-map": "^0.5.6", + "typescript": "~2.9.1", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "typescript": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.1.tgz", + "integrity": "sha512-h6pM2f/GDchCFlldnriOhs1QHuwbnmj6/v7499eMHqPeW4V2G0elua2eIc2nu8v2NdHV0Gm+tzX83Hr6nUFjQA==", + "dev": true + } + } + }, + "@angular-devkit/core": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.6.8.tgz", + "integrity": "sha512-rkIa1OSVWTt4g9leLSK/PsqOj3HZbDKHbZjqlslyfVa3AyCeiumFoOgViOVXlYgPX3HHDbE5uH24nyUWSD8uww==", + "dev": true, + "requires": { + "ajv": "~6.4.0", + "chokidar": "^2.0.3", + "rxjs": "^6.0.0", + "source-map": "^0.5.6" + } + }, + "@angular-devkit/schematics": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.6.8.tgz", + "integrity": "sha512-R4YqAUdo62wtrhX/5HSRGSKXNTWqfQb66ZE6m8jj6GEJNFKdNXMdxOchxr07LCiKTxfh1w6G3nGzxIsu/+D4KA==", + "dev": true, + "requires": { + "@angular-devkit/core": "0.6.8", + "rxjs": "^6.0.0" + } + }, + "@angular/animations": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-6.0.4.tgz", + "integrity": "sha512-Ro1XEwShk8XRAogfu73fKLTBLnND1s+MGhN+ymwr7ib9hqxVr7jMNE+MXPqG2/1BX9c+7NHb30B8G4woQn62vw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/cli": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.0.8.tgz", + "integrity": "sha512-DhH1Zq5Yonthw6zh6W07fhf+9XrAZbD1fcQ0MrmbxlieCfLlTAdBqyK2LavFCKwSZkUMLF6UHM3+jiNRVZSSIg==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.6.8", + "@angular-devkit/core": "0.6.8", + "@angular-devkit/schematics": "0.6.8", + "@schematics/angular": "0.6.8", + "@schematics/update": "0.6.8", + "opn": "~5.3.0", + "resolve": "^1.1.7", + "rxjs": "^6.0.0", + "semver": "^5.1.0", + "silent-error": "^1.0.0", + "symbol-observable": "^1.2.0", + "yargs-parser": "^10.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "yargs-parser": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.0.0.tgz", + "integrity": "sha512-+DHejWujTVYeMHLff8U96rLc4uE4Emncoftvn5AjhB1Jw1pWxLzgBUT/WYbPrHmy6YPEBTZQx5myHhVcuuu64g==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "@angular/common": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-6.0.4.tgz", + "integrity": "sha512-z2UE6a43u49omsqjzwdHhwD+wpCPauuD13FMkVQMLwzugKhNri0LjMk5I0I9xLz9OyXICm2B+wPAQN4d07savg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-6.0.4.tgz", + "integrity": "sha512-qwjuPacuRKUroD+xev653mljV9Jwhi2tvwGo/cVadq0isJ2rVH1hO6sa1FWFnNf1KPnyolMobZlMgg8DFW/yRw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/compiler-cli": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-6.0.4.tgz", + "integrity": "sha512-bkN21JJrsbIdXNfOc9I9iB7AETUe4/QvApC25R3/pERSyhkK7UNNHTqg4FY5xMdSxlZd1ccWj8rvSbS+hFbTBw==", + "dev": true, + "requires": { + "chokidar": "^1.4.2", + "minimist": "^1.2.0", + "reflect-metadata": "^0.1.2", + "tsickle": "^0.29.0" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "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" + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@angular/core": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-6.0.4.tgz", + "integrity": "sha512-WCW8wyRoIKkjGjOjVLFpUyhQw/K0//s3W0qo1/vH6m9njC63jP/VP+2Xnt8bdtgeET2NYUeyl+w/0vUXqYlnEA==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/forms": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-6.0.4.tgz", + "integrity": "sha512-JcKyCCkAwF3NlWuwPxtpRhFX/8QbFUkA4W0N62L+Odm8G0/P4QhMw/99o5kRs5xrsQRVyFlGvdYOrkgDyyZkGg==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/http": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-6.0.4.tgz", + "integrity": "sha512-bq7cS0/5hM3Af3FolEe7HpKP19/7MJWIPGi5k9rYCGM4dXKFiKa+LA/SbXE0DMiKxhAQbZDwQ9HN04r70DRyBQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/language-service": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-6.0.4.tgz", + "integrity": "sha512-LyFh/sFtnyjJJYO5UKM31nGSSkmGYFMwqzwbG+l0QNQXNoa9jj+OApvu0oOY5F0WP9DBrOAzj74j2M5olprtMQ==", + "dev": true + }, + "@angular/platform-browser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-6.0.4.tgz", + "integrity": "sha512-4y6rSqOLuBs+RL0CIM+RZ5T8a5Tm1NisZcTUGvM8lVYPNkqTzNfHQXhBq8mTgRw9JopEwOj+UEqBbgrNX715yQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-6.0.4.tgz", + "integrity": "sha512-uh7MoQi9kyKPFHrD7HPOU5gWyhF4pPJuGltyMTOtM/f5TNL9QQI2EugijKnnSFLQ8+7UQjmFAVeRqH9jylhIyQ==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@angular/router": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-6.0.4.tgz", + "integrity": "sha512-IKUtbbRtHN8I+Hp8/pLqBPyXJmQHrPFGzKU3H43TovD++mmT5AaYVCeJgkGUB//wjtLN3y0X/yrmyWFWcN35Gw==", + "requires": { + "tslib": "^1.9.0" + } + }, + "@ng-bootstrap/ng-bootstrap": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-2.2.0.tgz", + "integrity": "sha512-RUXYC00bTV/auJRRCUHFneOJStcLomKUTxpkp9GBdVNXmYaq+hg1IldHfWG7NLUEa7CcJ+vHB6YmKuktZ10HBw==", + "dev": true + }, + "@ngtools/webpack": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-6.0.8.tgz", + "integrity": "sha512-jorGpTd82ILbyUwg4JQekovHFaYwSMlZan4f7x+sd3+2WgyL3Z1+ZbVSGKvXZWKS/mAVx7eLkRikzJkuC4FgHw==", + "dev": true, + "requires": { + "@angular-devkit/core": "0.6.8", + "tree-kill": "^1.0.0", + "webpack-sources": "^1.1.0" + } + }, + "@schematics/angular": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.6.8.tgz", + "integrity": "sha512-9kRphqTYG5Df/I8fvnT1zMsw0YNDPO9tl18tQZXj4am4raT7l9UCr+WkwJdlBoA5pwG6baWE9sL0iGWV/bzF/g==", + "dev": true, + "requires": { + "@angular-devkit/core": "0.6.8", + "@angular-devkit/schematics": "0.6.8", + "typescript": ">=2.6.2 <2.8" + } + }, + "@schematics/update": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.6.8.tgz", + "integrity": "sha512-1Uq7LYnwL2wBwGVCgNz76QAR13ghAk+2vDDHOi+VX5+usHManxydrpoMGeX66OBPd+y5D3D2MFb+8mYHE7mygg==", + "dev": true, + "requires": { + "@angular-devkit/core": "0.6.8", + "@angular-devkit/schematics": "0.6.8", + "npm-registry-client": "^8.5.1", + "rxjs": "^6.0.0", + "semver": "^5.3.0", + "semver-intersect": "^1.1.2" + } + }, + "@types/d3": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-5.0.0.tgz", + "integrity": "sha512-BVfPw7ha+UgsG24v6ymerMY4+pJgQ/6p+hJA4loCeaaqV9snGS/G6ReVaQEn8Himn67dWn/Je9WhRbnDO7MzLw==", + "dev": true, + "requires": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-collection": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-voronoi": "*", + "@types/d3-zoom": "*" + } + }, + "@types/d3-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.1.tgz", + "integrity": "sha512-YBaAfimGdWE4nDuoGVKsH89/dkz2hWZ0i8qC+xxqmqi+XJ/aXiRF0jPtzXmN7VdkpVjy1xuDmM5/m1FNuB6VWA==", + "dev": true + }, + "@types/d3-axis": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.10.tgz", + "integrity": "sha512-5YF0wfdQMPKw01VAAupLIlg/T4pn5M3/vL9u0KZjiemnVnnKBEWE24na4X1iW+TfZiYJ8j+BgK2KFYnAAT54Ug==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-brush": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.0.8.tgz", + "integrity": "sha512-9Thv09jvolu9T1BE3fHmIeYSgbwSpdxtF6/A5HZEDjSTfgtA0mtaXRk5AiWOo0KjuLsI+/7ggD3ZGN5Ye8KXPQ==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-chord": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.7.tgz", + "integrity": "sha512-WbCN7SxhZMpQQw46oSjAovAmvl3IdjhLuQ4r7AXCzNKyxtXXBWuihSPZ4bVwFQF3+S2z37i9d4hfUBatcSJpog==", + "dev": true + }, + "@types/d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-vR3BT0GwHc5y93Jv6bxn3zoxP/vGu+GdXu/r1ApjbP9dLk9I2g6NiV7iP/QMQSuFZd0It0n/qWrfXHxCWwHIkg==", + "dev": true + }, + "@types/d3-color": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.2.1.tgz", + "integrity": "sha512-xwb1tqvYNWllbHuhMFhiXk63Imf+QNq/dJdmbXmr2wQVnwGenCuj3/0IWJ9hdIFQIqzvhT7T37cvx93jtAsDbQ==", + "dev": true + }, + "@types/d3-contour": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-1.2.1.tgz", + "integrity": "sha512-p8iC4KeVFyT3qRTGQRj0Jf5QDdPsDUevBEnma7gEsY1yDolVSLanG2eFAiLV+xj8/5DK7oU7Ey8z0drs3pbsug==", + "dev": true, + "requires": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "@types/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-xyWJQMr832vqhu6fD/YqX+MSFBWnkxasNhcStvlhqygXxj0cKqPft0wuGoH5TIq5ADXgP83qeNVa4R7bEYN3uA==", + "dev": true + }, + "@types/d3-drag": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.1.tgz", + "integrity": "sha512-J9liJ4NNeV0oN40MzPiqwWjqNi3YHCRtHNfNMZ1d3uL9yh1+vDuo346LBEr8yyBm30WHvrHssAkExVZrGCswtA==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-dsv": { + "version": "1.0.33", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.0.33.tgz", + "integrity": "sha512-jx5YvaVC3Wfh6LobaiWTeU1NkvL2wPmmpmajk618bD+xVz98yNWzmZMvmlPHGK0HXbMeHmW/6oVX48V9AH1bRQ==", + "dev": true + }, + "@types/d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha1-k6MBhovp4VBh89RDQ7GrP4rLbwk=", + "dev": true + }, + "@types/d3-fetch": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-1.1.2.tgz", + "integrity": "sha512-w6ANZv/mUh+6IV3drT22zgPWMRobzuGXhzOZC8JPD+ygce0/Vx6vTci3m3dizkocnQQCOwNbrWWWPYqpWiKzRQ==", + "dev": true, + "requires": { + "@types/d3-dsv": "*" + } + }, + "@types/d3-force": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.1.1.tgz", + "integrity": "sha512-ePkELuaFWY4yOuf+Bvx5Xd+ihFiYG4bdnW0BlvigovIm8Sob2t76e9RGO6lybQbv6AlW9Icn9HuZ9fmdzEoJyg==", + "dev": true + }, + "@types/d3-format": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.3.0.tgz", + "integrity": "sha512-ZiY4j3iJvAdOwzwW24WjlZbUNvqOsnPAMfPBmdXqxj3uKJbrzBlRrdGl5uC89pZpFs9Dc92E81KcwG2uEgkIZA==", + "dev": true + }, + "@types/d3-geo": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-1.10.3.tgz", + "integrity": "sha512-hfdaxM2L0wA9mDZrrSf2o+DyhEpnJYCiAN+lHFtpfZOVCQrYBA5g33sGRpUbAvjSMyO5jkHbftMWPEhuCMChSg==", + "dev": true, + "requires": { + "@types/geojson": "*" + } + }, + "@types/d3-hierarchy": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.3.tgz", + "integrity": "sha512-n08ySB4TZtoTAnhjym8CrCp0JZ/ItZlETtF66gXR1p34tISZ0drcxksxyvejtzzzIqvzTcWI1cUjTF3x2hkLUw==", + "dev": true + }, + "@types/d3-interpolate": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.2.0.tgz", + "integrity": "sha512-qM9KlUrqbwIhBRtw9OtAEbkis1AxsOJEun2uxaX/vEsBp3vyNBmhPz9boXXEqic9ZRi7fCpUNRwyZvxa0PioIw==", + "dev": true, + "requires": { + "@types/d3-color": "*" + } + }, + "@types/d3-path": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.7.tgz", + "integrity": "sha512-U8dFRG+8WhkLJr2sxZ9Cw/5WeRgBnNqMxGdA1+Z0+ZG6tK0s75OQ4OXnxeyfKuh6E4wQPY8OAKr1+iNDx01BEQ==", + "dev": true + }, + "@types/d3-polygon": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.6.tgz", + "integrity": "sha512-E6Kyodn9JThgLq20nxSbEce9ow5/ePgm9PX2EO6W1INIL4DayM7cFaiG10DStuamjYAd0X4rntW2q+GRjiIktw==", + "dev": true + }, + "@types/d3-quadtree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.6.tgz", + "integrity": "sha512-sphVuDdiSIaxLt9kQgebJW98pTktQ/xuN7Ysd8X68Rnjeg/q8+c36/ShlqU52qoKg9nob/JEHH1uQMdxURZidQ==", + "dev": true + }, + "@types/d3-random": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.1.tgz", + "integrity": "sha512-jUPeBq1XKK9/5XasTvy5QAUwFeMsjma2yt/nP02yC2Tijovx7i/W5776U/HZugxc5SSmtpx4Z3g9KFVon0QrjQ==", + "dev": true + }, + "@types/d3-scale": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-2.0.1.tgz", + "integrity": "sha512-D5ZWv8ToLvqacE7XkdMNHMiiVDULdDxT7FMMGU0YJC3/nVzBmApjyTyxracUWOQyY3KK7YhZ05on8pOcNi0dfQ==", + "dev": true, + "requires": { + "@types/d3-time": "*" + } + }, + "@types/d3-scale-chromatic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-1.2.0.tgz", + "integrity": "sha512-bhS2SVzUzRtrxp1REhGCfHmj8pyDv9oDmsonYiPvBl8KCxPJTxnfXBF39PzAJrYnRKM41TR0kQzsJvL+NmcDtg==", + "dev": true + }, + "@types/d3-selection": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.3.2.tgz", + "integrity": "sha512-K23sDOi7yMussv7aiqk097IWWbjFYbJpcDppQAcaf6DfmHxAsjr+6N4HJGokETLDuV7y/qJeeIJINPnkWJM5Hg==", + "dev": true + }, + "@types/d3-shape": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.2.3.tgz", + "integrity": "sha512-iP9TcX0EVi+LlX+jK9ceS+yhEz5abTitF+JaO2ugpRE/J+bccaYLe/0/3LETMmdaEkYarIyboZW8OF67Mpnj1w==", + "dev": true, + "requires": { + "@types/d3-path": "*" + } + }, + "@types/d3-time": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.0.8.tgz", + "integrity": "sha512-/UCphyyw97YAq4zKsuXH33R3UNB4jDSza0fLvMubWr/ONh9IePi1NbgFP222blhiCe724ebJs8U87+aDuAq/jA==", + "dev": true + }, + "@types/d3-time-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", + "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==", + "dev": true + }, + "@types/d3-timer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.7.tgz", + "integrity": "sha512-830pT+aYZrgbA91AuynP3KldfB1A1s60d0gKiV+L7JcSKSJapUzUffAm8VZod7RQOxF5SzoItV6cvrTzjbmrJQ==", + "dev": true + }, + "@types/d3-transition": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.1.2.tgz", + "integrity": "sha512-sTENKlKkUaKUYjeYIj69VYIi3VKeBinY/pYdy5VkjNmEOIasUtZIyAY04waMU4Rq7u+czKQdcP7Aoaf5wpDGfA==", + "dev": true, + "requires": { + "@types/d3-selection": "*" + } + }, + "@types/d3-voronoi": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.7.tgz", + "integrity": "sha512-/dHFLK5jhXTb/W4XEQcFydVk8qlIAo85G3r7+N2fkBFw190l0R1GQ8C1VPeXBb2GfSU5GbT2hjlnE7i7UY5Gvg==", + "dev": true + }, + "@types/d3-zoom": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.7.1.tgz", + "integrity": "sha512-Ofjwz6Pt53tRef9TAwwayN+JThNVYC/vFOepa/H4KtwjhsqkmEseHvc2jpJM7vye5PQ5XHtTSOpdY4Y/6xZWEg==", + "dev": true, + "requires": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "@types/geojson": { + "version": "7946.0.4", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.4.tgz", + "integrity": "sha512-MHmwBtCb7OCv1DSivz2UNJXPGU/1btAWRKlqJ2saEhVJkpkvqHMMaOpKg0v4sAbDWSQekHGvPVMM8nQ+Jen03Q==", + "dev": true + }, + "@types/jasmine": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.8.tgz", + "integrity": "sha512-OJSUxLaxXsjjhob2DBzqzgrkLmukM3+JMpRp0r0E4HTdT1nwDCWhaswjYxazPij6uOdzHCJfNbDjmQ1/rnNbCg==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.3.tgz", + "integrity": "sha512-hYDVmQZT5VA2kigd4H4bv7vl/OhlympwREUemqBdOqtrYTo5Ytm12a5W5/nGgGYdanGVxj0x/VhZ7J3hOg/YKg==", + "dev": true, + "requires": { + "@types/jasmine": "*" + } + }, + "@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/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "2.53.43", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz", + "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.4.3.tgz", + "integrity": "sha512-S6npYhPcTHDYe9nlsKa9CyWByFi8Vj8HovcAgtmMAQZUOczOZbQ8CnwMYKYC5HEZzxEE+oY0jfQk4cVlI3J59Q==", + "dev": true, + "requires": { + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/wast-parser": "1.4.3", + "debug": "^3.1.0", + "webassemblyjs": "1.4.3" + }, + "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" + } + } + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.4.3.tgz", + "integrity": "sha512-3zTkSFswwZOPNHnzkP9ONq4bjJSeKVMcuahGXubrlLmZP8fmTIJ58dW7h/zOVWiFSuG2em3/HH3BlCN7wyu9Rw==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.4.3.tgz", + "integrity": "sha512-e8+KZHh+RV8MUvoSRtuT1sFXskFnWG9vbDy47Oa166xX+l0dD5sERJ21g5/tcH8Yo95e9IN3u7Jc3NbhnUcSkw==", + "dev": true, + "requires": { + "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" + } + } + } + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.4.3.tgz", + "integrity": "sha512-9FgHEtNsZQYaKrGCtsjswBil48Qp1agrzRcPzCbQloCoaTbOXLJ9IRmqT+uEZbenpULLRNFugz3I4uw18hJM8w==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.4.3" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.4.3.tgz", + "integrity": "sha512-JINY76U+702IRf7ePukOt037RwmtH59JHvcdWbTTyHi18ixmQ+uOuNhcdCcQHTquDAH35/QgFlp3Y9KqtyJsCQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.4.3.tgz", + "integrity": "sha512-I7bS+HaO0K07Io89qhJv+z1QipTpuramGwUSDkwEaficbSvCcL92CUZEtgykfNtk5wb0CoLQwWlmXTwGbNZUeQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.4.3.tgz", + "integrity": "sha512-p0yeeO/h2r30PyjnJX9xXSR6EDcvJd/jC6xa/Pxg4lpfcNi7JUswOpqDToZQ55HMMVhXDih/yqkaywHWGLxqyQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-buffer": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/wasm-gen": "1.4.3", + "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" + } + } + } + }, + "@webassemblyjs/leb128": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.4.3.tgz", + "integrity": "sha512-4u0LJLSPzuRDWHwdqsrThYn+WqMFVqbI2ltNrHvZZkzFPO8XOZ0HFQ5eVc4jY/TNHgXcnwrHjONhPGYuuf//KQ==", + "dev": true, + "requires": { + "leb": "^0.3.0" + } + }, + "@webassemblyjs/validation": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/validation/-/validation-1.4.3.tgz", + "integrity": "sha512-R+rRMKfhd9mq0rj2mhU9A9NKI2l/Rw65vIYzz4lui7eTKPcCu1l7iZNi4b9Gen8D42Sqh/KGiaQNk/x5Tn/iBQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3" + } + }, + "@webassemblyjs/wasm-edit": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.4.3.tgz", + "integrity": "sha512-qzuwUn771PV6/LilqkXcS0ozJYAeY/OKbXIWU3a8gexuqb6De2p4ya/baBeH5JQ2WJdfhWhSvSbu86Vienttpw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-buffer": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/helper-wasm-section": "1.4.3", + "@webassemblyjs/wasm-gen": "1.4.3", + "@webassemblyjs/wasm-opt": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "@webassemblyjs/wast-printer": "1.4.3", + "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" + } + } + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.4.3.tgz", + "integrity": "sha512-eR394T8dHZfpLJ7U/Z5pFSvxl1L63JdREebpv9gYc55zLhzzdJPAuxjBYT4XqevUdW67qU2s0nNA3kBuNJHbaQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/leb128": "1.4.3" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.4.3.tgz", + "integrity": "sha512-7Gp+nschuKiDuAL1xmp4Xz0rgEbxioFXw4nCFYEmy+ytynhBnTeGc9W9cB1XRu1w8pqRU2lbj2VBBA4cL5Z2Kw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-buffer": "1.4.3", + "@webassemblyjs/wasm-gen": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "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" + } + } + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.4.3.tgz", + "integrity": "sha512-KXBjtlwA3BVukR/yWHC9GF+SCzBcgj0a7lm92kTOaa4cbjaTaa47bCjXw6cX4SGQpkncB9PU2hHGYVyyI7wFRg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/helper-wasm-bytecode": "1.4.3", + "@webassemblyjs/leb128": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "webassemblyjs": "1.4.3" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.4.3.tgz", + "integrity": "sha512-QhCsQzqV0CpsEkRYyTzQDilCNUZ+5j92f+g35bHHNqS22FppNTywNFfHPq8ZWZfYCgbectc+PoghD+xfzVFh1Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/floating-point-hex-parser": "1.4.3", + "@webassemblyjs/helper-code-frame": "1.4.3", + "@webassemblyjs/helper-fsm": "1.4.3", + "long": "^3.2.0", + "webassemblyjs": "1.4.3" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.4.3.tgz", + "integrity": "sha512-EgXk4anf8jKmuZJsqD8qy5bz2frEQhBvZruv+bqwNoLWUItjNSFygk8ywL3JTEz9KtxTlAmqTXNrdD1d9gNDtg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/wast-parser": "1.4.3", + "long": "^3.2.0" + } + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.6.2.tgz", + "integrity": "sha512-zUzo1E5dI2Ey8+82egfnttyMlMZ2y0D8xOCO3PNPPlYXpl8NZvF6Qk9L9BEtJs+43FqEmfBViDqc5d1ckRDguw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", + "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", + "dev": true, + "requires": { + "acorn": "^5.0.0" + } + }, + "adm-zip": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", + "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.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", + "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", + "dev": true, + "requires": { + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0", + "uri-js": "^3.0.2" + } + }, + "ajv-keywords": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.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" + } + } + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "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=", + "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" + } + }, + "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" + } + }, + "app-root-path": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.0.1.tgz", + "integrity": "sha1-zWLc+OT9WkF+/GZNLlsQZTxlG0Y=", + "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 + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "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" + } + }, + "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-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", + "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" + } + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "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.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=", + "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, + "optional": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "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.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "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 + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true, + "optional": 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.1", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", + "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "dev": true + }, + "autoprefixer": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-8.6.0.tgz", + "integrity": "sha512-JaYK4gmyklt+es0VDdWVS9R/X96D8eaT0qDLAO6R4niBsoKv6nI4QtfFs8YQskwatIdJ6XZeTBDRpjf4tH+Dlg==", + "dev": true, + "requires": { + "browserslist": "^3.2.8", + "caniuse-lite": "^1.0.30000847", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^6.0.22", + "postcss-value-parser": "^3.2.3" + } + }, + "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.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", + "dev": true + }, + "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": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "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" + } + }, + "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-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" + } + }, + "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" + } + }, + "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" + } + }, + "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=", + "dev": true + }, + "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" + } + } + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "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.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": 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": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "optional": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "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" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "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.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.1", + "http-errors": "~1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "~2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "~1.6.15" + }, + "dependencies": { + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "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" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.x.x" + } + }, + "bootstrap": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.1.tgz", + "integrity": "sha512-SpiDSOcbg4J/PjVSt4ny5eY6j74VbVSjROY4Fb/WIUXBV9cnb5luyR4KnPvNoXuGnBK1T+nJIWqRsvU3yP8Mcg==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "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" + } + } + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", + "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1" + } + }, + "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": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + } + }, + "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" + } + }, + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==", + "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": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "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": "10.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", + "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "dev": true, + "requires": { + "bluebird": "^3.5.1", + "chownr": "^1.0.1", + "glob": "^7.1.2", + "graceful-fs": "^4.1.11", + "lru-cache": "^4.1.1", + "mississippi": "^2.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^5.2.4", + "unique-filename": "^1.1.0", + "y18n": "^4.0.0" + } + }, + "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" + } + }, + "cache-loader": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cache-loader/-/cache-loader-1.2.2.tgz", + "integrity": "sha512-rsGh4SIYyB9glU+d0OcHwiXHXBoUgDhHZaQ1KAbiXqfz1CDPxtTboh1gPbJ0q2qdO8a9lfcjgC5CJ2Ms32y5bw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mkdirp": "^0.5.1", + "neo-async": "^2.5.0", + "schema-utils": "^0.4.2" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + } + } + }, + "caniuse-lite": { + "version": "1.0.30000849", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000849.tgz", + "integrity": "sha512-hlkWpyGJTDjjim2m+nvvHiEqt2PZuPdB9yYRbys5P/T179Aq7YgMF6tnM489voTfqMLtJhqmOZNfghxWjjT8jg==", + "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=", + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + } + }, + "chalk": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.2.tgz", + "integrity": "sha512-LvixLAQ4MYhbf7hgL4o5PeK32gJKvVzDRiSNIApDofQvyhl8adgG2lJVXn4+ekQoK7HL9RF8lqxwerpe0x2pCw==", + "dev": true, + "requires": { + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "chokidar": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", + "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.1.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.0" + } + }, + "chownr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", + "dev": true + }, + "chrome-trace-event": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-0.1.3.tgz", + "integrity": "sha512-sjndyZHrrWiu4RY7AkHgjn80GfAM2ZSzUkZLV/Js59Ldmh6JDThf0SUmOHU53rFu2rVxxfCzJ30Ukcfch3Gb/A==", + "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.0.2", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.0.2.tgz", + "integrity": "sha512-oC7/DVAyfcY3UWKm0sN/oVoDedQDQiw/vIiAnuTWTpE5s0zWf7l3WY417Xw/Fbi/QbAjctAkxgMiS9P0s3zkmA==", + "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.1.11", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.11.tgz", + "integrity": "sha1-Ls3xRaujj1R0DybO/Q/z4D4SXWo=", + "dev": true, + "requires": { + "source-map": "0.5.x" + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } + } + }, + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + }, + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^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": "4.2.1", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.2.1.tgz", + "integrity": "sha512-CKwfgpfkqi9dyzy4s6ELaxJ54QgJ6A8iTSsM4bzHbLuTpbKncvNc3DUlCvpnkHBhK47gEf4qFsWoYqLrJPhy6g==", + "dev": true, + "requires": { + "app-root-path": "^2.0.1", + "css-selector-tokenizer": "^0.7.0", + "cssauron": "^1.4.0", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.6", + "sprintf-js": "^1.0.3" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "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 + }, + "combine-lists": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", + "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", + "dev": true, + "requires": { + "lodash": "^4.5.0" + } + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "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.2.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.2.1.tgz", + "integrity": "sha512-2y2nHcopMG/NAyk6vWXlLs86XeM9sik4jmx1tKIgzMi9/RQ2eo758RGpxQO3ErihHmg0RlQITPqgz73y6s7quA==", + "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.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "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.14", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.14.tgz", + "integrity": "sha1-MmxfUH+7BV9UEWeCuWmoG2einac=", + "dev": true, + "requires": { + "mime-db": ">= 1.34.0 < 2" + }, + "dependencies": { + "mime-db": { + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.34.0.tgz", + "integrity": "sha1-RS0Oz/XDA0am3B5kseruDTcZ/5o=", + "dev": true + } + } + }, + "compression": { + "version": "1.7.2", + "resolved": "http://registry.npmjs.org/compression/-/compression-1.7.2.tgz", + "integrity": "sha1-qv+81qr4VLROuygDU9WtFlH1mmk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "bytes": "3.0.0", + "compressible": "~2.0.13", + "debug": "2.6.9", + "on-headers": "~1.0.1", + "safe-buffer": "5.1.1", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "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=", + "dev": true + }, + "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" + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "dependencies": { + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=", + "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" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "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.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "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 + }, + "convert-source-map": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "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": "4.5.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.5.1.tgz", + "integrity": "sha512-OlTo6DYg0XfTKOF8eLf79wcHm4Ut10xU2cRBRPMW/NA5F9VMjZGTfRHWDIYC3s+1kObGYrBLshXWU1K0hILkNQ==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "globby": "^7.1.1", + "is-glob": "^4.0.0", + "loader-utils": "^1.1.0", + "minimatch": "^3.0.4", + "p-limit": "^1.0.0", + "serialize-javascript": "^1.4.0" + } + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + }, + "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": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.4.3", + "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "os-homedir": "^1.0.1", + "parse-json": "^2.2.0", + "require-from-string": "^1.1.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "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": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.x.x" + } + }, + "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" + } + }, + "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-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", + "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + } + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "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 + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "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": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "d3": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-5.5.0.tgz", + "integrity": "sha512-HRDSYvT3n7kMvJH7Avp7iR0Xsz97bkCFka9aOg04EdyXyiAP8yQzUpLH3712y9R7ffVo1g94t1OYFHBB0yI9vQ==", + "dev": true, + "requires": { + "d3-array": "1", + "d3-axis": "1", + "d3-brush": "1", + "d3-chord": "1", + "d3-collection": "1", + "d3-color": "1", + "d3-contour": "1", + "d3-dispatch": "1", + "d3-drag": "1", + "d3-dsv": "1", + "d3-ease": "1", + "d3-fetch": "1", + "d3-force": "1", + "d3-format": "1", + "d3-geo": "1", + "d3-hierarchy": "1", + "d3-interpolate": "1", + "d3-path": "1", + "d3-polygon": "1", + "d3-quadtree": "1", + "d3-random": "1", + "d3-scale": "2", + "d3-scale-chromatic": "1", + "d3-selection": "1", + "d3-shape": "1", + "d3-time": "1", + "d3-time-format": "2", + "d3-timer": "1", + "d3-transition": "1", + "d3-voronoi": "1", + "d3-zoom": "1" + } + }, + "d3-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", + "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==", + "dev": true + }, + "d3-axis": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", + "integrity": "sha1-MacFoLU15ldZ3hQXOjGTMTfxjvo=", + "dev": true + }, + "d3-brush": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", + "integrity": "sha1-AMLyOAGfJPbAoZSibUGhUw/+e8Q=", + "dev": true, + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "d3-chord": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", + "integrity": "sha1-fexPC6iG9xP+ERxF92NBT290yiw=", + "dev": true, + "requires": { + "d3-array": "1", + "d3-path": "1" + } + }, + "d3-collection": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", + "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=", + "dev": true + }, + "d3-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.2.0.tgz", + "integrity": "sha512-dmL9Zr/v39aSSMnLOTd58in2RbregCg4UtGyUArvEKTTN6S3HKEy+ziBWVYo9PTzRyVW+pUBHUtRKz0HYX+SQg==", + "dev": true + }, + "d3-contour": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.0.tgz", + "integrity": "sha512-6zccxidQRtcydx0lWqHawdW1UcBzKZTxv0cW90Dlx98pY/L7GjQJmftH1tWopYFDaLCoXU0ECg9x/z2EuFT8tg==", + "dev": true, + "requires": { + "d3-array": "^1.1.1" + } + }, + "d3-dispatch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", + "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=", + "dev": true + }, + "d3-drag": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", + "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", + "dev": true, + "requires": { + "d3-dispatch": "1", + "d3-selection": "1" + } + }, + "d3-dsv": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", + "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", + "dev": true, + "requires": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + } + }, + "d3-ease": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", + "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=", + "dev": true + }, + "d3-fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.0.tgz", + "integrity": "sha512-j+V4vtT6dceQbcKYLtpTueB8Zvc+wb9I93WaFtEQIYNADXl0c1ZJMN3qQo0CssiTsAqK8pePwc7f4qiW+b0WOg==", + "dev": true, + "requires": { + "d3-dsv": "1" + } + }, + "d3-force": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", + "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", + "dev": true, + "requires": { + "d3-collection": "1", + "d3-dispatch": "1", + "d3-quadtree": "1", + "d3-timer": "1" + } + }, + "d3-format": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.3.0.tgz", + "integrity": "sha512-ycfLEIzHVZC3rOvuBOKVyQXSiUyCDjeAPIj9n/wugrr+s5AcTQC2Bz6aKkubG7rQaQF0SGW/OV4UEJB9nfioFg==", + "dev": true + }, + "d3-geo": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.10.0.tgz", + "integrity": "sha512-VK/buVGgexthTTqGRNXQ/LSo3EbOFu4p2Pjud5drSIaEnOaF2moc8A3P7WEljEO1JEBEwbpAJjFWMuJiUtoBcw==", + "dev": true, + "requires": { + "d3-array": "1" + } + }, + "d3-hierarchy": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.6.tgz", + "integrity": "sha512-nn4bhBnwWnMSoZgkBXD7vRyZ0xVUsNMQRKytWYHhP1I4qHw+qzApCTgSQTZqMdf4XXZbTMqA59hFusga+THA/g==", + "dev": true + }, + "d3-interpolate": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.2.0.tgz", + "integrity": "sha512-zLvTk8CREPFfc/2XglPQriAsXkzoRDAyBzndtKJWrZmHw7kmOWHNS11e40kPTd/oGk8P5mFJW5uBbcFQ+ybxyA==", + "dev": true, + "requires": { + "d3-color": "1" + } + }, + "d3-path": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", + "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=", + "dev": true + }, + "d3-polygon": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", + "integrity": "sha1-FoiOkCZGCTPysXllKtN4Ik04LGI=", + "dev": true + }, + "d3-quadtree": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", + "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=", + "dev": true + }, + "d3-random": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", + "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=", + "dev": true + }, + "d3-scale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.1.0.tgz", + "integrity": "sha512-Bb2N3ZgzPdKVEoWGkt8lPV6R7YdpSBWI70Xf26NQHOVjs77a6gLUmBOOPt9d9nB8JiQhwXY1RHCa+eSyWCJZIQ==", + "dev": true, + "requires": { + "d3-array": "^1.2.0", + "d3-collection": "1", + "d3-format": "1", + "d3-interpolate": "1", + "d3-time": "1", + "d3-time-format": "2" + } + }, + "d3-scale-chromatic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.3.0.tgz", + "integrity": "sha512-YwMbiaW2bStWvQFByK8hA6hk7ToWflspIo2TRukCqERd8isiafEMBXmwfh8c7/0Z94mVvIzIveRLVC6RAjhgeA==", + "dev": true, + "requires": { + "d3-color": "1", + "d3-interpolate": "1" + } + }, + "d3-selection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", + "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==", + "dev": true + }, + "d3-shape": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", + "integrity": "sha1-RdAVOPBkuv0F6j1tLLdI/YxB93c=", + "dev": true, + "requires": { + "d3-path": "1" + } + }, + "d3-time": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", + "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==", + "dev": true + }, + "d3-time-format": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", + "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "dev": true, + "requires": { + "d3-time": "1" + } + }, + "d3-timer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", + "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==", + "dev": true + }, + "d3-transition": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", + "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", + "dev": true, + "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.2", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", + "integrity": "sha1-Fodmfo8TotFYyAwUgMWinLDYlzw=", + "dev": true + }, + "d3-zoom": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.1.tgz", + "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", + "dev": true, + "requires": { + "d3-dispatch": "1", + "d3-drag": "1", + "d3-interpolate": "1", + "d3-selection": "1", + "d3-transition": "1" + } + }, + "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-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": "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" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "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 + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "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" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "^2.0.5", + "object-keys": "^1.0.8" + } + }, + "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" + } + } + } + }, + "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" + }, + "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 + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "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.3", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", + "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", + "dev": true + }, + "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 + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "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-converter": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", + "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", + "dev": true, + "requires": { + "utila": "~0.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "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" + } + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "~1.1.1", + "entities": "~1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "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 + }, + "domelementtype": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "duplexify": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", + "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "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.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "~0.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 + }, + "ejs": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz", + "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.48", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz", + "integrity": "sha1-07DYWTgUBE4JLs4hCPw6ya6kuQA=", + "dev": true + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "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" + } + }, + "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 + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.3.tgz", + "integrity": "sha1-jef5eJXSDTm4X4ju7nd7K9QrE9Q=", + "dev": true, + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "ws": "1.1.2" + }, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "dev": true, + "requires": { + "mime-types": "~2.1.11", + "negotiator": "0.6.1" + } + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "ws": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz", + "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=", + "dev": true, + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + } + } + }, + "engine.io-client": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.3.tgz", + "integrity": "sha1-F5jtk0USRkU9TG9jXXogH+lA1as=", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parsejson": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "1.1.2", + "xmlhttprequest-ssl": "1.5.3", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "ws": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz", + "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=", + "dev": true, + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + } + } + }, + "engine.io-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", + "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.6", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary": "0.1.7", + "wtf-8": "1.0.0" + } + }, + "enhanced-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz", + "integrity": "sha512-jox/62b2GofV1qTUQTMPEJSDIGycS43evqYzD/KVtEb9OCoki9cnacUPxCrZa7JfPzZSYOCZhu9O9luaMxAX8g==", + "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.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "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.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.1.1", + "function-bind": "^1.1.1", + "has": "^1.0.1", + "is-callable": "^1.1.3", + "is-regex": "^1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "^1.1.1", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.1" + } + }, + "es5-ext": { + "version": "0.10.45", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", + "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "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" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "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=", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + } + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "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" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + } + } + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "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": "3.1.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "eventsource": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", + "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", + "dev": true, + "requires": { + "original": ">=0.0.5" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "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" + }, + "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" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-braces": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "dev": true, + "requires": { + "array-slice": "^0.2.3", + "array-unique": "^0.2.1", + "braces": "^0.1.2" + }, + "dependencies": { + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "dev": true, + "requires": { + "expand-range": "^0.1.0" + } + }, + "expand-range": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "dev": true, + "requires": { + "is-number": "^0.1.1", + "repeat-string": "^0.2.2" + } + }, + "is-number": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", + "dev": true + }, + "repeat-string": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", + "dev": true + } + } + }, + "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": { + "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" + } + } + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + }, + "dependencies": { + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "express": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", + "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "~1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.1.1", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.3", + "qs": "6.5.1", + "range-parser": "~1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.2", + "serve-static": "1.13.2", + "setprototypeof": "1.1.0", + "statuses": "~1.4.0", + "type-is": "~1.6.16", + "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 + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "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" + } + } + } + }, + "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" + } + } + } + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "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 + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastparse": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", + "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", + "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" + } + }, + "file-loader": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^0.4.5" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "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": "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" + } + } + } + }, + "finalhandler": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.4.0", + "unpipe": "~1.0.0" + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flush-write-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", + "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "follow-redirects": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz", + "integrity": "sha512-fdrt472/9qQ6Kgjvb935ig6vJCuofpBUD14f9Vb+SLlm7xIe4Qva5gey8EKtv8lp7ahE1wilg3xL1znpVGtZIA==", + "dev": true, + "requires": { + "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" + } + } + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "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.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "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 + }, + "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-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=", + "dev": true + }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.5.1", + "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.2", + "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.21", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "^2.1.0" + } + }, + "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 + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": 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, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "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 + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": 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.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.5.1", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "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.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true, + "dev": 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.5.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, + "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, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": true + } + } + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": 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" + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "optional": true, + "requires": { + "globule": "^1.0.0" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true, + "optional": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "optional": true, + "requires": { + "is-property": "^1.0.0" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "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 + }, + "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.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "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" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^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" + } + } + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "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" + } + }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "dev": true, + "optional": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "handle-thing": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", + "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, + "dependencies": { + "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" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "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=", + "dev": true, + "optional": true + } + } + } + } + }, + "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.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.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" + } + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "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=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "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=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "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": { + "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" + } + } + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "optional": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "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" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "hosted-git-info": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", + "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", + "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 + }, + "html-minifier": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.16.tgz", + "integrity": "sha512-zP5EfLSpiLRp0aAgud4CQXPQZm9kXwWjR/cF0PfdOj+jjWnOaCgeZcll4kYXSvIBPeUMmyaSc7mM4IDtA+kboA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.1.x", + "commander": "2.15.x", + "he": "1.1.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.3.x" + } + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "dev": true, + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.1", + "domutils": "1.1", + "readable-stream": "1.0" + }, + "dependencies": { + "domutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "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.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" + } + }, + "http-parser-js": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz", + "integrity": "sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc=", + "dev": true + }, + "http-proxy": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, + "requires": { + "eventemitter3": "^3.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz", + "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==", + "dev": true, + "requires": { + "http-proxy": "^1.16.2", + "is-glob": "^4.0.0", + "lodash": "^4.17.5", + "micromatch": "^3.1.9" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "dev": true, + "requires": { + "agent-base": "^4.1.0", + "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" + } + } + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "ieee754": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", + "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", + "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.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.8.tgz", + "integrity": "sha512-pUh+xUQQhQzevjRHHFqqcTy0/dP/kS9I8HSrUydhihjuD09W6ldVWFtIrwhXdUJHis3i2rZNqEHpZH/cbinFbg==", + "dev": true + }, + "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-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", + "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "dev": true, + "requires": { + "pkg-dir": "^2.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true, + "optional": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "internal-ip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", + "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", + "dev": true, + "requires": { + "meow": "^3.3.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": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ipaddr.js": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", + "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=", + "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" + }, + "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" + } + } + } + }, + "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": "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-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "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" + }, + "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" + } + } + } + }, + "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=", + "dev": true + }, + "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-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "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": "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" + } + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true, + "optional": true + }, + "is-my-json-valid": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", + "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "dev": true, + "optional": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.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" + }, + "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" + } + } + } + }, + "is-odd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", + "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", + "dev": true, + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "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" + } + }, + "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-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true, + "optional": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "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-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "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 + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", + "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", + "dev": true + }, + "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": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "istanbul-api": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.1.tgz", + "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==", + "dev": true, + "requires": { + "async": "^2.1.4", + "compare-versions": "^3.1.0", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-hook": "^1.2.0", + "istanbul-lib-instrument": "^1.10.1", + "istanbul-lib-report": "^1.1.4", + "istanbul-lib-source-maps": "^1.2.4", + "istanbul-reports": "^1.3.0", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" + }, + "dependencies": { + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + } + } + }, + "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" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", + "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz", + "integrity": "sha512-eLAMkPG9FU0v5L02lIkcj/2/Zlz9OuluaXikdr5iStk8FDbSwAixTK9TkYxbF0eNnzAJTwM2fkV2A1tpsIp4Jg==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", + "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", + "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.0", + "semver": "^5.3.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz", + "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^1.2.0", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" + }, + "dependencies": { + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz", + "integrity": "sha512-8O2T/3VhrQHn0XcJbP1/GN7kXMiRAlPi+fj3uEHrjBD8Oz7Py0prSC25C09NuAZS6bgW1NNKAvCSHZXB0irSGA==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.0", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + }, + "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" + } + } + } + }, + "istanbul-reports": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.3.0.tgz", + "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==", + "dev": true, + "requires": { + "handlebars": "^4.0.3" + } + }, + "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": "2.99.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", + "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", + "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 + }, + "js-base64": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz", + "integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ==", + "dev": true, + "optional": true + }, + "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 + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + } + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "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.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "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 + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true, + "optional": 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.1.5", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", + "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", + "dev": true, + "requires": { + "core-js": "~2.3.0", + "es6-promise": "~3.0.2", + "lie": "~3.1.0", + "pako": "~1.0.2", + "readable-stream": "~2.0.6" + }, + "dependencies": { + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", + "dev": true + }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "karma": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz", + "integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==", + "dev": true, + "requires": { + "bluebird": "^3.3.0", + "body-parser": "^1.16.1", + "chokidar": "^1.4.1", + "colors": "^1.1.0", + "combine-lists": "^1.0.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "expand-braces": "^0.1.1", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^3.8.0", + "log4js": "^0.6.31", + "mime": "^1.3.4", + "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": "1.7.3", + "source-map": "^0.5.3", + "tmp": "0.0.31", + "useragent": "^2.1.12" + }, + "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "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" + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + } + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-2.0.1.tgz", + "integrity": "sha512-UcgrHkFehI5+ivMouD8NH/UOHiX4oCAtwaANylzPFdcAuD52fnCUuelacq2gh8tZ4ydhU3+xiXofSq7j5Ehygw==", + "dev": true, + "requires": { + "istanbul-api": "^1.3.1", + "minimatch": "^3.0.4" + } + }, + "karma-jasmine": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.2.tgz", + "integrity": "sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM=", + "dev": true + }, + "karma-jasmine-html-reporter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", + "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", + "dev": true, + "requires": { + "karma-jasmine": "^1.0.2" + } + }, + "karma-source-map-support": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz", + "integrity": "sha512-HcPqdAusNez/ywa+biN4EphGz62MmQyPggUsDfsHqa7tSe4jdsxgvTKuDfIazjL+IOxpVWyT7Pr4dhAV+sxX5Q==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "killable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz", + "integrity": "sha1-2ouEvUfeU5WHj5XWTQLyRJ/gXms=", + "dev": true + }, + "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 + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "leb": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/leb/-/leb-0.3.0.tgz", + "integrity": "sha1-Mr7p+tFoMo1q6oUi2DP0GA7tHaM=", + "dev": true + }, + "less": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/less/-/less-3.0.4.tgz", + "integrity": "sha512-q3SyEnPKbk9zh4l36PGeW2fgynKu+FpbhiUNx/yaiBUQ3V0CbACCgb9FzYWcRgI2DJlP6eI4jc8XPrCTi55YcQ==", + "dev": true, + "requires": { + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.1.0.tgz", + "integrity": "sha512-KNTsgCE9tMOM70+ddxp9yyt9iHqgmSs0yTZc5XH5Wo+g80RWRIYNqE58QJKm/yMud5wZEvz50ugRDuzVIkyahg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "loader-utils": "^1.1.0", + "pify": "^3.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "license-webpack-plugin": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-1.3.1.tgz", + "integrity": "sha512-NqAFodJdpBUuf1iD+Ij8hQvF0rCFKlO2KaieoQzAPhFgzLCtJnC7Z7x5gQbGNjoe++wOKAtAmwVEIBLqq2Yp1A==", + "dev": true, + "requires": { + "ejs": "^2.5.7" + } + }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loader-runner": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", + "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true, + "optional": true + }, + "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 + }, + "lodash.mergewith": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", + "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", + "dev": true, + "optional": true + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", + "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" + } + }, + "log4js": { + "version": "0.6.38", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz", + "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=", + "dev": true, + "requires": { + "readable-stream": "~1.0.2", + "semver": "~4.3.3" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "semver": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "dev": true + }, + "loglevelnext": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz", + "integrity": "sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A==", + "dev": true, + "requires": { + "es6-symbol": "^3.1.1", + "object.assign": "^4.1.0" + } + }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "^3.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "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" + } + }, + "make-error": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", + "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "dev": true + }, + "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-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "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" + } + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true + }, + "md5.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.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" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "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 + }, + "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" + } + }, + "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.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "~1.33.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 + }, + "mini-css-extract-plugin": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.4.0.tgz", + "integrity": "sha512-2Zik6PhUZ/MbiboG6SDS9UTPL4XXy4qnyGjSdCIWRrr8xb6PwLtHE+AYOjkXJWdF0OG8vo/yrJ8CgS5WbMpzIg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.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==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mississippi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", + "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "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": "^2.0.1", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "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" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } + }, + "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" + } + }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=", + "dev": true + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "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 + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", + "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "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-odd": "^2.0.0", + "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" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "neo-async": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", + "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "ng-inline-svg": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ng-inline-svg/-/ng-inline-svg-8.0.0.tgz", + "integrity": "sha512-BxrT+G0Zim3rbakdlFzILsm3ICmAG0V6F74r2esgxLKiA5EdNGCc0btdfzWDLHfFCa6w7ZZco1nlunJ2lr7Ucw==" + }, + "ngx-cookie-service": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ngx-cookie-service/-/ngx-cookie-service-1.0.10.tgz", + "integrity": "sha512-TAXpQsIONAupTqkUDcH44hFQsLTvsXpxM80eKgxvy3vhBFfT1uIdR7BRhM7VpUW5J7BN9qCbGNgLN5lsnVu7pw==" + }, + "ngx-slimscroll": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/ngx-slimscroll/-/ngx-slimscroll-7.1.0.tgz", + "integrity": "sha512-DkR4fWKgxmpaN75gJ96WXS9ztq2YufiPn0xqeKP3Q7b+UxryLsjWS4niteXsvNfynmA77En2wSavSQc36s7knQ==" + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", + "dev": true + }, + "node-gyp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", + "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "dev": true, + "optional": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "2", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true, + "optional": true + } + } + }, + "node-libs-browser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", + "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", + "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": "^1.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.0", + "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.10.3", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-sass": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", + "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", + "dev": true, + "optional": true, + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash.assign": "^4.2.0", + "lodash.clonedeep": "^4.3.2", + "lodash.mergewith": "^4.6.0", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.10.0", + "node-gyp": "^3.3.1", + "npmlog": "^4.0.0", + "request": "~2.79.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, + "optional": true + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "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" + } + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "optional": true, + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "optional": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true, + "optional": true + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "qs": "~6.3.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1", + "uuid": "^3.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true, + "optional": true + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "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" + } + }, + "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 + }, + "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" + } + }, + "npm-registry-client": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/npm-registry-client/-/npm-registry-client-8.5.1.tgz", + "integrity": "sha512-7rjGF2eA7hKDidGyEWmHTiKfXkbrcQAsGL/Rh4Rt3x3YNRNHhwaTzVJfW3aNvvlhg4G62VCluif0sLCb/i51Hg==", + "dev": true, + "requires": { + "concat-stream": "^1.5.2", + "graceful-fs": "^4.1.6", + "normalize-package-data": "~1.0.1 || ^2.0.0", + "npm-package-arg": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0", + "npmlog": "2 || ^3.1.0 || ^4.0.0", + "once": "^1.3.3", + "request": "^2.74.0", + "retry": "^0.10.0", + "safe-buffer": "^5.1.1", + "semver": "2 >=2.2.1 || 3.x || 4 || 5", + "slide": "^1.1.3", + "ssri": "^5.2.4" + } + }, + "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" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "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.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "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" + } + }, + "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" + } + } + } + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "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.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.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.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "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": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, + "original": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.1.tgz", + "integrity": "sha512-IEvtB5vM5ULvwnqMxWBLxkS13JIEXbakizMSo3yoPNPCIWzg8TG3Usn/UhXoZFM/m+FuEA20KdzPSFq/0rS+UA==", + "dev": true, + "requires": { + "url-parse": "~1.4.0" + } + }, + "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": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "optional": true, + "requires": { + "lcid": "^1.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-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "dev": true + }, + "parallel-transform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", + "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", + "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" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "dependencies": { + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + } + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.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 + }, + "parsejson": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", + "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "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.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "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.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "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=", + "dev": true + }, + "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.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "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" + } + }, + "pbkdf2": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", + "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", + "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 + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "portfinder": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", + "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", + "dev": true, + "requires": { + "async": "^1.5.2", + "debug": "^2.2.0", + "mkdirp": "0.5.x" + } + }, + "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": "6.0.22", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.22.tgz", + "integrity": "sha512-Toc9lLoUASwGqxBSJGTVcOQiDqjK+Z2XlWBg+IgYwQMY9vA2f7iMpXVc1GpPcfTSyM5lkxNo0oDwDRO+wm7XHA==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.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 + } + } + }, + "postcss-import": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", + "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", + "dev": true, + "requires": { + "postcss": "^6.0.1", + "postcss-value-parser": "^3.2.3", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0", + "postcss-load-options": "^1.2.0", + "postcss-load-plugins": "^2.3.0" + } + }, + "postcss-load-options": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", + "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.0", + "object-assign": "^4.1.0" + } + }, + "postcss-load-plugins": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", + "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", + "dev": true, + "requires": { + "cosmiconfig": "^2.1.1", + "object-assign": "^4.1.0" + } + }, + "postcss-loader": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.5.tgz", + "integrity": "sha512-pV7kB5neJ0/1tZ8L1uGOBNTVBCSCXQoIsZMsrwvO8V2rKGa2tBl/f80GGVxow2jJnRJ2w1ocx693EKhZAb9Isg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "postcss": "^6.0.0", + "postcss-load-config": "^1.2.0", + "schema-utils": "^0.4.0" + } + }, + "postcss-url": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.3.2.tgz", + "integrity": "sha512-QMV5mA+pCYZQcUEPQkmor9vcPQ2MT+Ipuu8qdi1gVxbNiIiErEGft+eny1ak19qALoBkccS5AHaCaCDzh7b9MA==", + "dev": true, + "requires": { + "mime": "^1.4.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.0", + "postcss": "^6.0.1", + "xxhashjs": "^0.2.1" + } + }, + "postcss-value-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", + "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "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 + }, + "protractor": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.3.2.tgz", + "integrity": "sha512-pw4uwwiy5lHZjIguxNpkEwJJa7hVz+bJsvaTI+IbXlfn2qXwzbF8eghW/RmrZwE2sGx82I8etb8lVjQ+JrjejA==", + "dev": true, + "requires": { + "@types/node": "^6.0.46", + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "~2.53.39", + "blocking-proxy": "^1.0.0", + "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": "^1.0.0", + "webdriver-manager": "^12.0.6" + }, + "dependencies": { + "@types/node": { + "version": "6.0.112", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.112.tgz", + "integrity": "sha512-HnekQWq9t3Gl5aBYYi8sGyOWm85M5ub2llMrpQkRY94eJEUhsUr8qYNaeefv22cxxm+D67a+5zIzpl+dpFxdjQ==", + "dev": true + }, + "adm-zip": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.11.tgz", + "integrity": "sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "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" + } + }, + "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" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "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" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "webdriver-manager": { + "version": "12.0.6", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", + "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", + "dev": true, + "requires": { + "adm-zip": "^0.4.7", + "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.78.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + } + } + } + }, + "proxy-addr": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", + "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.6.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 + }, + "public-encrypt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", + "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "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.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.0.0.tgz", + "integrity": "sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw==", + "dev": true + }, + "randomatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", + "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "randombytes": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", + "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "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.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "dev": true, + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true + } + } + }, + "raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=", + "dev": true + }, + "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-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "dependencies": { + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.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" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "minimatch": "^3.0.2", + "readable-stream": "^2.0.2", + "set-immediate-shim": "^1.0.1" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "reflect-metadata": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", + "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==", + "dev": true + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "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" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "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 + }, + "renderkid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", + "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "~0.1", + "htmlparser2": "~3.3.0", + "strip-ansi": "^3.0.0", + "utila": "~0.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "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=", + "dev": true + }, + "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.87.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", + "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + }, + "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-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "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.7.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", + "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "dev": true, + "requires": { + "path-parse": "^1.0.5" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "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 + }, + "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.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "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=", + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.1" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "^7.0.5" + } + }, + "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" + } + }, + "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=", + "dev": true + }, + "rxjs": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.2.0.tgz", + "integrity": "sha512-qBzf5uu6eOKiCZuAE0SgZ0/Qp+l54oeVxFfC2t+mJ2SFI6IB8gmMdJHs5DUMu5kqifqcCtsKS2XHjhZu6RKvAw==", + "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==", + "dev": true + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "optional": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true, + "optional": true + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + } + } + } + }, + "sass-loader": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.0.3.tgz", + "integrity": "sha512-iaSFtQcGo4SSgDw5Aes5p4VTrA5jCGSA7sGmhPIcOloBlgI1VktM2MUrk2IHHjbNagckXlPz+HWq1vAAPrcYxA==", + "dev": true, + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0" + } + }, + "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": "0.4.5", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", + "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "optional": true, + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.3.tgz", + "integrity": "sha512-vmZenZ+8Al3NLHkWnhBQ0x6BkML1eCP2xEi3JE+f3D9wW9fipD9NNJHYtE9XJM4TsPaHGZJIamrSI6MTg1dU2Q==", + "dev": true, + "requires": { + "node-forge": "0.7.5" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "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" + } + }, + "semver-intersect": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.3.1.tgz", + "integrity": "sha1-j6hKnhAovSOeRTDRo+GB5pjYhLo=", + "dev": true, + "requires": { + "semver": "^5.0.0" + } + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "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.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "dependencies": { + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", + "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "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" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "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.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "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 + }, + "silent-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz", + "integrity": "sha1-IglwbxyFCp8dENDYQJGLRvJuG8k=", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "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": { + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + }, + "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" + } + } + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "optional": true, + "requires": { + "hoek": "2.x.x" + } + }, + "socket.io": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.3.tgz", + "integrity": "sha1-uK+cq6AJSeVo42nxMn6pvp6iRhs=", + "dev": true, + "requires": { + "debug": "2.3.3", + "engine.io": "1.8.3", + "has-binary": "0.1.7", + "object-assign": "4.1.0", + "socket.io-adapter": "0.5.0", + "socket.io-client": "1.7.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + }, + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "dev": true + } + } + }, + "socket.io-adapter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", + "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", + "dev": true, + "requires": { + "debug": "2.3.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "socket.io-client": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.3.tgz", + "integrity": "sha1-sw6GqhDV7zVGYBwJzeR2Xjgdo3c=", + "dev": true, + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.3.3", + "engine.io-client": "1.8.3", + "has-binary": "0.1.7", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.5", + "socket.io-parser": "2.3.1", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "dev": true, + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true + } + } + }, + "socket.io-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", + "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", + "dev": true, + "requires": { + "component-emitter": "1.1.2", + "debug": "2.2.0", + "isarray": "0.0.1", + "json3": "3.3.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=", + "dev": true + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "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.1.4", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", + "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", + "dev": true, + "requires": { + "debug": "^2.6.6", + "eventsource": "0.1.6", + "faye-websocket": "~0.11.0", + "inherits": "^2.0.1", + "json3": "^3.3.2", + "url-parse": "^1.1.8" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + } + } + }, + "source-list-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "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-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.5.6", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz", + "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", + "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 + } + } + }, + "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 + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "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.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "dev": true + }, + "spdy": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", + "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "dev": true, + "requires": { + "debug": "^2.6.8", + "handle-thing": "^1.2.5", + "http-deceiver": "^1.2.7", + "safe-buffer": "^5.0.1", + "select-hose": "^2.0.0", + "spdy-transport": "^2.0.18" + } + }, + "spdy-transport": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.1.0.tgz", + "integrity": "sha512-bpUeGpZcmZ692rrTiqf9/2EUakI6/kXX1Rpe0ib/DyOzbiexVfXkw6GnvI9hVGvIwVaUhkaBojjCZwLNRGQg1g==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "detect-node": "^2.0.3", + "hpack.js": "^2.1.6", + "obuf": "^1.1.1", + "readable-stream": "^2.2.9", + "safe-buffer": "^5.0.1", + "wbuf": "^1.7.2" + } + }, + "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 + }, + "sshpk": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "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": "5.3.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", + "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "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" + } + } + } + }, + "stats-webpack-plugin": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/stats-webpack-plugin/-/stats-webpack-plugin-0.6.2.tgz", + "integrity": "sha1-LFlJtTHgf4eojm6k3PrFOqjHWis=", + "dev": true, + "requires": { + "lodash": "^4.17.4" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "stdout-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", + "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", + "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", + "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 + }, + "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" + } + }, + "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" + } + }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true, + "optional": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "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-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "style-loader": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.21.0.tgz", + "integrity": "sha512-T+UNsAcl3Yg+BsPKs1vd22Fr8sVT+CJMtzqc6LEw9bbJZb43lm9GoeIfUcDEefBSWC0BhYbcdupV1GtI4DGzxg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^0.4.5" + } + }, + "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" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "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": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "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 + }, + "tapable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", + "integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "optional": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "^2.1.5", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", + "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.1" + } + }, + "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": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "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" + }, + "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" + } + } + } + }, + "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": "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" + } + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "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.0", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz", + "integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==", + "dev": true + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "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 + }, + "true-case-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", + "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "dev": true, + "optional": true, + "requires": { + "glob": "^6.0.4" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "ts-node": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-5.0.1.tgz", + "integrity": "sha512-XK7QmDcNHVmZkVtkiwNDWiERRHPyU8nBqZB1+iv2UhOG0q3RQ9HsZ2CMqISlFbxjrYFGfG2mX7bW4dAyxBVzUw==", + "dev": true, + "requires": { + "arrify": "^1.0.0", + "chalk": "^2.3.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.3", + "yn": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "tsickle": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.29.0.tgz", + "integrity": "sha512-JpID0Lv8/irRtPmqJJxb5fCwfZhjZeKmav9Zna7UjqVuJoSbI49Wue/c2PPybX1SbRrjl7bbI/JsCl0dSUJygA==", + "dev": true, + "requires": { + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map": "^0.6.0", + "source-map-support": "^0.5.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "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 + } + } + }, + "tslib": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.2.tgz", + "integrity": "sha512-AVP5Xol3WivEr7hnssHDsaM+lVrVXWUvd1cfXTRkTj80b//6g2wIFEH6hZG0muGZRnHGrfttpdzRk3YlBkWjKw==" + }, + "tslint": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.10.0.tgz", + "integrity": "sha1-EeJrzLiK+gLdDZlWyuPUVAtfVMM=", + "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.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.12.1" + }, + "dependencies": { + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "tsutils": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.27.1.tgz", + "integrity": "sha512-AE/7uzp32MmaHvNNFES85hhUDHFdFZp6OAiZcd6y4ZKKIg6orJTm8keYWBhIhrJQH3a4LzNKat7ZPXZt5aTf6w==", + "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, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.7.2.tgz", + "integrity": "sha512-p5TCYZDAO0m4G344hD+wx/LATebLWZNkkh2asWUFqSsD2OrDNhbAHuSjobrmsUmdzjJjEeZVU9g1h3O6vpstnw==", + "dev": true + }, + "uglify-js": { + "version": "3.3.28", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.28.tgz", + "integrity": "sha512-68Rc/aA6cswiaQ5SrE979UJcXX+ADA1z33/ZsPd+fbAiVdjZ16OXdbtGO+rJUUBgK6qdf3SOPhQf3K/ybF5Miw==", + "dev": true, + "requires": { + "commander": "~2.15.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 + } + } + }, + "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=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz", + "integrity": "sha512-hIQJ1yxAPhEA2yW/i7Fr+SXZVMp+VEI3d42RTHBgQd2yhp/1UdBcR3QEWPV5ahBxlqQDMEMTuTEvDHSFINfwSw==", + "dev": true, + "requires": { + "cacache": "^10.0.4", + "find-cache-dir": "^1.0.0", + "schema-utils": "^0.4.5", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "uglify-es": "^3.3.4", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "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 + }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "dev": true, + "requires": { + "commander": "~2.13.0", + "source-map": "~0.6.1" + } + } + } + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "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" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unique-filename": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", + "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", + "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "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 + } + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "uri-js": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", + "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", + "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-join": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.0.tgz", + "integrity": "sha1-TTNA6AfTdzvamZH4MFrNzCpmXSo=", + "dev": true + }, + "url-loader": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.0.1.tgz", + "integrity": "sha512-rAonpHy7231fmweBKUFe0bYnlGDty77E+fm53NZdij7j/YOpyGzc7ttqG1nAXl3aRs0k41o0PC3TvGXQiw2Zvw==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "mime": "^2.0.3", + "schema-utils": "^0.4.3" + }, + "dependencies": { + "mime": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", + "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "dev": true + } + } + }, + "url-parse": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.1.tgz", + "integrity": "sha512-x95Td74QcvICAA0+qERaVkRpTGKyBHHYdwL2LXZm5t/gBtCB9KQSO/0zQgSTYEV1p0WcvSg79TLNPSvd5IDJMQ==", + "dev": true, + "requires": { + "querystringify": "^2.0.0", + "requires-port": "^1.0.0" + } + }, + "use": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", + "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "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" + } + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "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": "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" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "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.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "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 + }, + "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": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "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" + } + }, + "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" + } + }, + "webassemblyjs": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webassemblyjs/-/webassemblyjs-1.4.3.tgz", + "integrity": "sha512-4lOV1Lv6olz0PJkDGQEp82HempAn147e6BXijWDzz9g7/2nSebVP9GVg62Fz5ZAs55mxq13GA0XLyvY8XkyDjg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/validation": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "@webassemblyjs/wast-parser": "1.4.3", + "long": "^3.2.0" + } + }, + "webdriver-js-extender": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", + "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", + "dev": true, + "requires": { + "@types/selenium-webdriver": "^2.53.35", + "selenium-webdriver": "^2.53.2" + }, + "dependencies": { + "sax": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", + "dev": true + }, + "selenium-webdriver": { + "version": "2.53.3", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", + "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", + "dev": true, + "requires": { + "adm-zip": "0.4.4", + "rimraf": "^2.2.8", + "tmp": "0.0.24", + "ws": "^1.0.1", + "xml2js": "0.4.4" + } + }, + "tmp": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", + "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", + "dev": true + }, + "xml2js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", + "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", + "dev": true, + "requires": { + "sax": "0.6.x", + "xmlbuilder": ">=1.0.0" + } + } + } + }, + "webpack": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.8.3.tgz", + "integrity": "sha512-/hfAjBISycdK597lxONjKEFX7dSIU1PsYwC3XlXUXoykWBlv9QV5HnO+ql3HvrrgfBJ7WXdnjO9iGPR2aAc5sw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.4.3", + "@webassemblyjs/wasm-edit": "1.4.3", + "@webassemblyjs/wasm-parser": "1.4.3", + "acorn": "^5.0.0", + "acorn-dynamic-import": "^3.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chrome-trace-event": "^0.1.1", + "enhanced-resolve": "^4.0.0", + "eslint-scope": "^3.7.1", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "micromatch": "^3.1.8", + "mkdirp": "~0.5.0", + "neo-async": "^2.5.0", + "node-libs-browser": "^2.0.0", + "schema-utils": "^0.4.4", + "tapable": "^1.0.0", + "uglifyjs-webpack-plugin": "^1.2.4", + "watchpack": "^1.5.0", + "webpack-sources": "^1.0.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.1.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.1.3.tgz", + "integrity": "sha512-I6Mmy/QjWU/kXwCSFGaiOoL5YEQIVmbb0o45xMoCyQAg/mClqZVTcsX327sPfekDyJWpCxb+04whNyLOIxpJdQ==", + "dev": true, + "requires": { + "loud-rejection": "^1.6.0", + "memory-fs": "~0.4.1", + "mime": "^2.1.0", + "path-is-absolute": "^1.0.0", + "range-parser": "^1.0.3", + "url-join": "^4.0.0", + "webpack-log": "^1.0.1" + }, + "dependencies": { + "mime": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.3.1.tgz", + "integrity": "sha512-OEUllcVoydBHGN1z84yfQDimn58pZNNNXgZlHXSboxMlFvgI6MXSWpWKpFRra7H1HxpVhHTkrghfRW49k6yjeg==", + "dev": true + } + } + }, + "webpack-dev-server": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.1.4.tgz", + "integrity": "sha512-itcIUDFkHuj1/QQxzUFOEXXmxOj5bku2ScLEsOFPapnq2JRTm58gPdtnBphBJOKL2+M3p6+xygL64bI+3eyzzw==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "array-includes": "^3.0.3", + "bonjour": "^3.5.0", + "chokidar": "^2.0.0", + "compression": "^1.5.2", + "connect-history-api-fallback": "^1.3.0", + "debug": "^3.1.0", + "del": "^3.0.0", + "express": "^4.16.2", + "html-entities": "^1.2.0", + "http-proxy-middleware": "~0.18.0", + "import-local": "^1.0.0", + "internal-ip": "1.2.0", + "ip": "^1.1.5", + "killable": "^1.0.0", + "loglevel": "^1.4.1", + "opn": "^5.1.0", + "portfinder": "^1.0.9", + "selfsigned": "^1.9.1", + "serve-index": "^1.7.2", + "sockjs": "0.3.19", + "sockjs-client": "1.1.4", + "spdy": "^3.4.1", + "strip-ansi": "^3.0.0", + "supports-color": "^5.1.0", + "webpack-dev-middleware": "3.1.3", + "webpack-log": "^1.1.2", + "yargs": "11.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 + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "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" + } + } + } + }, + "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" + } + }, + "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 + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "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": { + "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" + } + } + } + }, + "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 + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", + "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.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", + "yargs-parser": "^9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } + } + } + }, + "webpack-log": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz", + "integrity": "sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "log-symbols": "^2.1.0", + "loglevelnext": "^1.0.1", + "uuid": "^3.1.0" + } + }, + "webpack-merge": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.2.tgz", + "integrity": "sha512-/0QYwW/H1N/CdXYA2PNPVbsxO3u2Fpz34vs72xm03SRfg6bMNGfMJIQEpQjKRvkG2JvT6oRJFpDtSrwbX8Jzvw==", + "dev": true, + "requires": { + "lodash": "^4.17.5" + } + }, + "webpack-sources": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", + "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", + "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.4", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.1.0-rc.4.tgz", + "integrity": "sha1-xcTj1pD50vZKlVDgeodn+Xlqpdg=", + "dev": true, + "requires": { + "webpack-core": "^0.6.8" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": ">=0.4.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": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "worker-farm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", + "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.2.tgz", + "integrity": "sha1-iiRPoFJAHgjJiGz0SoUYnh/UBn8=", + "dev": true, + "requires": { + "options": ">=0.0.5", + "ultron": "1.0.x" + } + }, + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=", + "dev": true + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + }, + "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": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlhttprequest-ssl": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", + "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "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": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "optional": 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 + }, + "zone.js": { + "version": "0.8.26", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.26.tgz", + "integrity": "sha512-W9Nj+UmBJG251wkCacIkETgra4QgBo/vgoEkb4a2uoLzpQG7qF9nzwoLXWU5xj3Fg2mxGvEDh47mg24vXccYjA==" + } + } +} diff --git a/gui/package.json b/gui/package.json new file mode 100644 index 00000000..3339ab3b --- /dev/null +++ b/gui/package.json @@ -0,0 +1,57 @@ +{ + "name": "gui", + "version": "0.0.0", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "^6.0.3", + "@angular/common": "^6.0.3", + "@angular/compiler": "^6.0.3", + "@angular/core": "^6.0.3", + "@angular/forms": "^6.0.3", + "@angular/http": "^6.0.3", + "@angular/platform-browser": "^6.0.3", + "@angular/platform-browser-dynamic": "^6.0.3", + "@angular/router": "^6.0.3", + "bootstrap": "^4.1.1", + "core-js": "^2.5.4", + "ng-inline-svg": "^8.0.0", + "ngx-cookie-service": "^1.0.10", + "rxjs": "^6.0.0", + "zone.js": "^0.8.26", + "ngx-slimscroll": "^7.1.0" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.6.6", + "@angular/cli": "^6.0.8", + "@angular/compiler-cli": "^6.0.3", + "@angular/language-service": "^6.0.3", + "@ng-bootstrap/ng-bootstrap": "^2.2.0", + "@types/d3": "^5.0.0", + "@types/jasmine": "~2.8.6", + "@types/jasminewd2": "~2.0.3", + "@types/node": "~8.9.4", + "codelyzer": "~4.2.1", + "d3": "^5.5.0", + "jasmine-core": "~2.99.1", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~1.7.1", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.0", + "karma-jasmine": "~1.1.1", + "karma-jasmine-html-reporter": "^0.2.2", + "moment": "^2.22.2", + "protractor": "~5.3.0", + "ts-node": "~5.0.1", + "tslint": "^5.10.0", + "typescript": "^2.7.2", + "ngx-slimscroll": "^7.1.0" + } +} diff --git a/gui/src/app/app.component.html b/gui/src/app/app.component.html new file mode 100644 index 00000000..0680b43f --- /dev/null +++ b/gui/src/app/app.component.html @@ -0,0 +1 @@ + diff --git a/gui/src/app/app.component.scss b/gui/src/app/app.component.scss new file mode 100644 index 00000000..4b1b06cc --- /dev/null +++ b/gui/src/app/app.component.scss @@ -0,0 +1,17 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +app-main-page { + display: block; +} diff --git a/gui/src/app/app.component.spec.ts b/gui/src/app/app.component.spec.ts new file mode 100644 index 00000000..08637ec4 --- /dev/null +++ b/gui/src/app/app.component.spec.ts @@ -0,0 +1,46 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + // Shared test components + // All should be set in beforeEach() + let fixture: ComponentFixture = null; + let app: any = null; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + AppComponent + ], + schemas: [ NO_ERRORS_SCHEMA ], + }).compileComponents(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + app = fixture.debugElement.componentInstance; + }); + + it('should create the app', () => { + expect(app).toBeTruthy(); + }); + + it(`should have as title 'Pure1 Unplugged'`, () => { + expect(app.title).toEqual('Pure1 Unplugged'); + }); +}); diff --git a/gui/src/app/app.component.ts b/gui/src/app/app.component.ts new file mode 100644 index 00000000..255501a7 --- /dev/null +++ b/gui/src/app/app.component.ts @@ -0,0 +1,28 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent implements OnInit { + title = 'Pure1 Unplugged'; + + constructor() {} + + ngOnInit() { } +} diff --git a/gui/src/app/app.module.ts b/gui/src/app/app.module.ts new file mode 100644 index 00000000..01958d13 --- /dev/null +++ b/gui/src/app/app.module.ts @@ -0,0 +1,50 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { AppComponent } from './app.component'; +import { AppRoutingModule } from './modules/app-routing/app-routing.module'; +import { MainPageComponent } from './modules/core/components/main-page/main-page.component'; +import { SidebarComponent } from './modules/core/components/sidebar/sidebar.component'; +import { CoreModule } from './modules/core/core.module'; +import { DashboardModule } from './modules/dashboard/dashboard.module'; +import { DeviceModule } from './modules/device/device.module'; +import { SupportModule } from './modules/support/support.module'; + +@NgModule({ + declarations: [ + AppComponent, + MainPageComponent, + SidebarComponent + ], + imports: [ + BrowserModule, + HttpClientModule, + DeviceModule, + DashboardModule, + SupportModule, + CoreModule, + AppRoutingModule, + InlineSVGModule.forRoot(), + NgbTooltipModule.forRoot(), + FormsModule, + ], + bootstrap: [AppComponent] +}) +export class AppModule { } diff --git a/gui/src/app/modules/app-routing/app-routing.module.spec.ts b/gui/src/app/modules/app-routing/app-routing.module.spec.ts new file mode 100644 index 00000000..8ecd0c51 --- /dev/null +++ b/gui/src/app/modules/app-routing/app-routing.module.spec.ts @@ -0,0 +1,27 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { AppRoutingModule } from './app-routing.module'; + +describe('AppRoutingModule', () => { + let appRoutingModule: AppRoutingModule; + + beforeEach(() => { + appRoutingModule = new AppRoutingModule(); + }); + + it('should create an instance', () => { + expect(appRoutingModule).toBeTruthy(); + }); +}); diff --git a/gui/src/app/modules/app-routing/app-routing.module.ts b/gui/src/app/modules/app-routing/app-routing.module.ts new file mode 100644 index 00000000..d95ef562 --- /dev/null +++ b/gui/src/app/modules/app-routing/app-routing.module.ts @@ -0,0 +1,66 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { MainPageComponent } from '../core/components/main-page/main-page.component'; +import { ArrayCapacityComponent } from '../dashboard/components/array-capacity/array-capacity.component'; +import { ArrayPerformanceComponent } from '../dashboard/components/array-performance/array-performance.component'; +import { CapacityDashboardComponent } from '../dashboard/components/capacity-dashboard/capacity-dashboard.component'; +import { + FilesystemPerformanceComponent +} from '../dashboard/components/filesystem-performance/filesystem-performance.component'; +import { MainDashboardComponent } from '../dashboard/components/main-dashboard/main-dashboard.component'; +import { PerformanceDashboardComponent } from '../dashboard/components/performance-dashboard/performance-dashboard.component'; +import { VolumePerformanceComponent } from '../dashboard/components/volume-performance/volume-performance.component'; +import { AlertsViewComponent } from '../device-alert/components/alerts-view/alerts-view.component'; +import { DeviceAlertModule } from '../device-alert/device-alert.module'; +import { DeviceListComponent } from '../device/components/device-list/device-list.component'; +import { SupportComponent } from '../support/components/support/support.component'; + +const routes: Routes = [ + { path: '', redirectTo: 'dash', pathMatch: 'full'}, + { path: 'dash', component: MainPageComponent, + children: [ + // Default path/page (what the user sees when they first log in) is set here in "redirectTo" + { path: '', redirectTo: 'arrays', pathMatch: 'full'}, + { path: 'dashboard', component: MainDashboardComponent }, + { path: 'arrays', component: DeviceListComponent }, + { path: 'analytics/performance', component: PerformanceDashboardComponent, + children: [ + { path: 'arrays', component: ArrayPerformanceComponent }, + { path: 'filesystems', component: FilesystemPerformanceComponent }, + { path: 'volumes', component: VolumePerformanceComponent }, + { path: '**', redirectTo: 'arrays' } + ] + }, + { path: 'analytics/capacity', component: CapacityDashboardComponent, + children: [ + { path: 'arrays', component: ArrayCapacityComponent }, + { path: '**', redirectTo: 'arrays' } + ] + }, + { path: 'analytics', redirectTo: 'analytics/performance' }, // Default analytics path + { path: 'troubleshooting', component: SupportComponent }, + { path: 'messages', component: AlertsViewComponent } + ] + }, + { path: '**', redirectTo: 'dash'} +]; + +@NgModule({ + exports: [ RouterModule ], + imports: [ RouterModule.forRoot(routes), DeviceAlertModule ] +}) +export class AppRoutingModule {} diff --git a/gui/src/app/modules/core/components/alert-indicator/alert-indicator.component.html b/gui/src/app/modules/core/components/alert-indicator/alert-indicator.component.html new file mode 100644 index 00000000..b6b51cbb --- /dev/null +++ b/gui/src/app/modules/core/components/alert-indicator/alert-indicator.component.html @@ -0,0 +1,3 @@ + +
+
diff --git a/gui/src/app/modules/core/components/alert-indicator/alert-indicator.component.ts b/gui/src/app/modules/core/components/alert-indicator/alert-indicator.component.ts new file mode 100644 index 00000000..a4c29bcd --- /dev/null +++ b/gui/src/app/modules/core/components/alert-indicator/alert-indicator.component.ts @@ -0,0 +1,37 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input } from '@angular/core'; + +type severity = 'critical' | 'warning' | 'info' | 'none'; + +@Component({ + selector: 'alert-indicator', + templateUrl: './alert-indicator.component.html' +}) +export class AlertIndicatorComponent { + @Input() severity: severity; + @Input() isDisabled = false; + @Input() iconWidth = '20px'; + @Input() iconHeight = '20px'; + + data = { + none: { svg: 'assets/icons/secondary/alert_info.svg', class: 'pstg-card-flip-icon' }, + info: { svg: 'assets/icons/secondary/alert_info.svg', class: 'pstg-alert-info-icon' }, + warning: { svg: 'assets/icons/secondary/alert_warning.svg', class: 'pstg-alert-warning-icon' }, + critical: { svg: 'assets/icons/secondary/alert_critical.svg', class: 'pstg-alert-critical-icon' } + }; + + constructor() { } +} diff --git a/gui/src/app/modules/core/components/dial/dial.component.scss b/gui/src/app/modules/core/components/dial/dial.component.scss new file mode 100644 index 00000000..128d1545 --- /dev/null +++ b/gui/src/app/modules/core/components/dial/dial.component.scss @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.background-arc { + fill: #eaeaea; +} + +.data-arc.ok { + fill: #71a74f; +} + +.data-arc.warning { + fill: #fac13a; +} + +.data-arc.critical { + fill: #f33b2e; +} diff --git a/gui/src/app/modules/core/components/dial/dial.component.ts b/gui/src/app/modules/core/components/dial/dial.component.ts new file mode 100644 index 00000000..a12cb0bf --- /dev/null +++ b/gui/src/app/modules/core/components/dial/dial.component.ts @@ -0,0 +1,108 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { AfterViewInit, Component, Input, OnChanges, OnInit, QueryList, SimpleChanges, + ViewChildren, ViewEncapsulation } from '@angular/core'; +import * as d3 from 'd3'; + +@Component({ + selector: 'dial', + template: '', + styleUrls: ['./dial.component.scss'], + encapsulation: ViewEncapsulation.None, +}) +export class DialComponent implements OnInit, AfterViewInit, OnChanges { + + @Input() size = 125; + @Input() percentFull = 0.0; + @Input() status: 'ok' | 'warning' | 'critical' = 'ok'; + @Input() centerLabel = ''; + @Input() labelSize = '12px'; + + @ViewChildren('dialContainer') dialContainer: QueryList; + + private dataArc: any; + private backgroundArc: any; + private isInitialized = false; // yes + private svgElem: any; // yes + + constructor() { } + + ngOnInit() { } + + ngAfterViewInit() { + this.initD3(); + } + + ngOnChanges(changes: SimpleChanges) { + if (!this.isInitialized) { return; } // If this isn't initialized we can't do anything yet + + this.drawLabel(); + this.drawArcs(); + } + + private initD3(): void { + this.svgElem = d3.select(this.dialContainer.first.nativeElement) + .attr('width', this.size) + .attr('height', this.size); + + this.drawLabel(); + + // Draw background arc + this.backgroundArc = d3.arc() + .innerRadius(this.size / 2 - this.size * .12) + .outerRadius(this.size / 2) + .startAngle(0) + .endAngle(Math.PI * 2); + + this.svgElem.append('path') + .attr('d', this.backgroundArc) + .attr('transform', 'translate(' + (this.size / 2) + ',' + (this.size / 2) + ')') + .attr('class', 'background-arc'); + this.drawArcs(); + + this.isInitialized = true; + } + + private drawLabel(): void { + this.svgElem.selectAll('.center-label').remove(); + + this.svgElem.append('text') + .attr('text-anchor', 'middle') + .attr('y', '50%') + .attr('x', '50%') + .attr('dy', '0.35em') + .attr('font-size', this.labelSize) + .attr('fill', '#717171') + .attr('class', 'center-label') + .text(this.centerLabel); + } + + private drawArcs(): void { + this.svgElem.selectAll('.data-arc').remove(); + + // Draw data arc + this.dataArc = d3.arc() + .innerRadius(this.size / 2 - this.size * .12) + .outerRadius(this.size / 2) + .startAngle(0) + .endAngle(Math.PI * 2 * this.percentFull); + + this.svgElem.append('path') + .attr('d', this.dataArc) + .attr('transform', 'translate(' + (this.size / 2) + ',' + (this.size / 2) + ')') + .attr('class', 'data-arc ' + this.status); + } + +} diff --git a/gui/src/app/modules/core/components/main-page/main-page.component.html b/gui/src/app/modules/core/components/main-page/main-page.component.html new file mode 100644 index 00000000..5d1b17fe --- /dev/null +++ b/gui/src/app/modules/core/components/main-page/main-page.component.html @@ -0,0 +1,53 @@ +
+ + +
+
+
+ +

{{sidebar?.activeTab?.title}}

+
+ +
+
+
+
+ {{username}} + Admin +
+
+ + + +
+
+
+ +
+
+
+
+ + + Log Out + +
+
+
+ +
+
+
diff --git a/gui/src/app/modules/core/components/main-page/main-page.component.scss b/gui/src/app/modules/core/components/main-page/main-page.component.scss new file mode 100644 index 00000000..3b8b7a7a --- /dev/null +++ b/gui/src/app/modules/core/components/main-page/main-page.component.scss @@ -0,0 +1,259 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#page-wrapper { + height: 100vh; + background-color: #454545; + padding-left: 204px; + transition: padding-left .5s ease; +} + +#page-wrapper.smallWindow { + padding-left: 0px; +} + +#page-wrapper.retracted { + padding-left: 70px; +} + +#page-wrapper.smallWindow.retracted { + padding-left: 0px; +} + +#topbar, #topbar-right { + position: fixed; + z-index: 1001; +} + +#page-wrapper #page-content-wrapper { + position: relative; + width: 100%; + height: 100%; + top: 0; + left: 0; + float: right; +} + +#page-wrapper.smallWindow #page-content-wrapper { + opacity: 0.5; +} + +#page-wrapper.smallWindow.retracted #page-content-wrapper { + opacity: 1.0; +} + +#topbar { + width: 100%; + top: 0; + height: 55px; + border-bottom: 1px solid #c5c5c5; + background-color: #dedede; + margin: 0; + position: fixed; +} + +#topbar .page-title { + display: inline-block; + padding: 0 0 0 20px; + margin: 0; + line-height: 55px; + font-size: 20px; + font-weight: 600; +} + +#page-wrapper #toggle-icon { + display: none; +} + +#page-wrapper.smallWindow #toggle-icon { + display: block; +} + +#topbar #toggle-icon { + float: left; + margin-top: 12px; + margin-left: 8px; + width: 30px; + height: 30px; +} + +#topbar, #topbar-right { + position: fixed; + z-index: 1001; +} + +#topbar-right { + top: 5px; + right: 10px; + height: 45px; +} + +#topbar-right .topbar-item-summary { + border-right: 1px solid #c5c5c5 +} + +#topbar-right .topbar-item { + height: 100%; + display: inline-block; + padding: 0 10px; +} + +#topbar-right .topbar-icon-with-count .topbar-icon { + display: inline-block; + height: 20px; + vertical-align: bottom; +} + +#topbar-right .topbar-icon-with-count { + display: inline-block; + position: relative; + line-height: 32.5px; + padding: 0 5px; +} + +#topbar-right .topbar-icon-with-count .tooltip-span { + position: absolute; + top: 100%; + left: 0; + width: 100%; +} + +#topbar-right .topbar-item-user { + cursor: pointer; +} + +#topbar-right .p-profile-user .p-profile-icon { + display: inline-block; + height: 30px; + width: 30px; + float: left; + margin-top: 5px; + margin-left: 12px; +} + +#topbar-right .p-profile-user .p-profile-greeting { + text-align: left; + padding-top: 5px; + line-height: 15px; +} + +#topbar-right .p-profile-user .p-profile-greeting .p-profile-text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-weight: 400; + font-size: 13px; + color: #454545; +} + +#topbar-right .p-profile-user .p-profile-greeting .p-profile-text.p-profile-name { + display: block; + font-weight: 600; + width: auto; + padding-right: 20px; +} + +#topbar-right .p-profile-user .p-profile-greeting .p-profile-text.p-profile-role { + font-size: 12px; + color: #797979; +} + +#topbar-right .p-profile-user .pureui-collapse-btn { + position: absolute; + top: 9px; + right: 10px; + overflow: visible; + font-size: 16px; +} + +#tab-content { + margin-top: 55px; + position: relative; + margin-left: auto; + margin-right: auto; + padding-right: 0px; + padding-left: 0px; + background-color: #e6e6e6; + height: auto; + min-height: calc(100% - 55px); +} + +h1, h2, h3 { + color: #454545 +} + +::ng-deep .user-window-caret svg { + transition: transform .3s ease; + fill: #454545; + height: 16px; +} + +::ng-deep .user-window-caret.opened svg { + transform: scaleY(-1); +} + +* { + /* Bootstrap, in its current setup, likes to override fonts. This fixes it. */ + font-family: "Proxima Nova",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif; +} + +.logout-modal-wrapper { + overflow: hidden; + height: 35px; + width: 120px; + margin-top: 20px; + position: absolute; + right: 0px; + top: 0px; + z-index: 999; + transition: margin .3s ease; +} + +.logout-modal-wrapper.open { + margin-top: 55px; +} + +.logout-modal { + background-color: #ffffff; + margin-left: 5px; + padding: 20px; + padding-top: 0px; + height: 30px; + width: 110px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); +} + +#pureui-logout-text { + display: inline-block; + height: 30px; + line-height: 30px; + color: #8d8d8d; + fill: #8d8d8d; + cursor: pointer; + float: right; +} + +.modal-logout-icon { + position: relative; + right: 8px; + top: 5px; + width: 20px; + height: 20px; +} + +.user-window-caret { + width: 8px; +} diff --git a/gui/src/app/modules/core/components/main-page/main-page.component.spec.ts b/gui/src/app/modules/core/components/main-page/main-page.component.spec.ts new file mode 100644 index 00000000..bfaa531a --- /dev/null +++ b/gui/src/app/modules/core/components/main-page/main-page.component.spec.ts @@ -0,0 +1,143 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HttpClient, HttpHandler } from '@angular/common/http'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { RouterTestingModule } from '@angular/router/testing'; +import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import * as moment from 'moment'; +import { CookieService } from 'ngx-cookie-service'; +import { DeviceAlertService } from '../../../device-alert/device-alert.service'; +import { SidebarComponent } from '../sidebar/sidebar.component'; +import { MainPageComponent } from './main-page.component'; + +describe('MainPageComponent', () => { + let component: MainPageComponent; + let fixture: ComponentFixture; + let nativeElem: any = null; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MainPageComponent ], + imports: [ NgbTooltipModule.forRoot(), RouterTestingModule ], + providers: [ SidebarComponent, CookieService, DeviceAlertService, HttpClient, HttpHandler ], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MainPageComponent); + component = fixture.componentInstance; + nativeElem = fixture.debugElement.nativeElement; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should start expanded', () => { + expect(nativeElem.querySelector('#page-wrapper').classList.contains('retracted')).toBeFalsy(); + }); + + it('should have a sidebar', () => { + expect(nativeElem.querySelector('#page-wrapper sidebar')).toBeTruthy(); + }); +}); + +describe('TokenEmailParser', () => { + it('should fail on an null token', () => { + expect(MainPageComponent.getTokenEmail(null)).toEqual(MainPageComponent.invalidTokenCookieMessage); + }); + + it('should fail on an undefined token', () => { + expect(MainPageComponent.getTokenEmail(undefined)).toEqual(MainPageComponent.invalidTokenCookieMessage); + }); + + it('should fail on an empty token', () => { + expect(MainPageComponent.getTokenEmail('')).toEqual(MainPageComponent.invalidTokenCookieMessage); + }); + + it('should fail on a malformed token (not enough segments)', () => { + expect(MainPageComponent.getTokenEmail('a.a')).toEqual(MainPageComponent.invalidTokenCookieMessage); + }); + + it('should fail on an invalid claims section (invalid Base64)', () => { + expect(MainPageComponent.getTokenEmail('a.aaaaa.a')).toEqual(MainPageComponent.invalidTokenCookieMessage); + }); + + it('should fail on an invalid claims section (invalid JSON)', () => { + // "{{[--bad;json::{?" in Base64 + expect(MainPageComponent.getTokenEmail('a.e3tbLS1iYWQ7anNvbjo6ez8=.a')).toEqual(MainPageComponent.invalidTokenCookieMessage); + }); + + it('should fail on an invalid claims section (missing email)', () => { + // "{"not-email": "pureuser@purestorage.com"}" in Base64 + expect(MainPageComponent.getTokenEmail('a.eyJub3QtZW1haWwiOiAicHVyZXVzZXJAcHVyZXN0b3JhZ2UuY29tIn0=.a')) + .toEqual(MainPageComponent.invalidTokenCookieMessage); + }); + + it('should succeed on a valid token', () => { + // "{"email": "pureuser@purestorage.com"}" in Base64 + expect(MainPageComponent.getTokenEmail('a.eyJlbWFpbCI6ICJwdXJldXNlckBwdXJlc3RvcmFnZS5jb20ifQ==.a')).toEqual('pureuser@purestorage.com'); + }); +}); + +describe('TokenExpirationParser', () => { + it('should fail on a null token', () => { + expect(MainPageComponent.getTokenExpiryTime(null)).toBeNull(); + }); + + it('should fail on an undefined token', () => { + expect(MainPageComponent.getTokenExpiryTime(undefined)).toBeNull(); + }); + + it('should fail on an empty token', () => { + expect(MainPageComponent.getTokenExpiryTime('')).toBeNull(); + }); + + it('should fail on a malformed token (not enough segments)', () => { + expect(MainPageComponent.getTokenExpiryTime('a.a')).toBeNull(); + }); + + it('should fail on an invalid claims section (invalid Base64)', () => { + expect(MainPageComponent.getTokenExpiryTime('a.aaaaa.a')).toBeNull(); + }); + + it('should fail on an invalid claims section (invalid JSON)', () => { + // "{{[--bad;json::{?" in Base64 + expect(MainPageComponent.getTokenExpiryTime('a.e3tbLS1iYWQ7anNvbjo6ez8=.a')).toBeNull(); + }); + + it('should fail on an invalid claims section (missing exp)', () => { + // "{"not-exp": 1561590164}" in Base64 + expect(MainPageComponent.getTokenExpiryTime('a.eyJub3QtZXhwIjoxNTYxNTkwMTY0fQ.a')).toBeNull(); + }); + + it('should fail on an invalid claims section (non-numeric exp)', () => { + // "{"exp":"asdf"}" in Base64 + expect(MainPageComponent.getTokenExpiryTime('a.eyJleHAiOiJhc2RmIn0=.a')).toBeNull(); + }); + + it('should succeed on a valid token', () => { + const claims = btoa(JSON.stringify({ + exp: moment().unix() + 5 + })); + const token = `a.${claims}.a`; + expect(MainPageComponent.getTokenExpiryTime(token)).toBe(5); + }); +}); diff --git a/gui/src/app/modules/core/components/main-page/main-page.component.ts b/gui/src/app/modules/core/components/main-page/main-page.component.ts new file mode 100644 index 00000000..5455b7a5 --- /dev/null +++ b/gui/src/app/modules/core/components/main-page/main-page.component.ts @@ -0,0 +1,208 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpClient } from '@angular/common/http'; +import { Component, HostListener, OnInit, ViewChild } from '@angular/core'; +import * as moment from 'moment'; +import { CookieService } from 'ngx-cookie-service'; +import { isNullOrUndefined } from 'util'; +import { DeviceAlert } from '../../../../shared/models/device-alert'; +import { DeviceAlertQuery } from '../../../../shared/models/device-alert-query'; +import { DeviceAlertService } from '../../../device-alert/device-alert.service'; +import { DeviceService } from '../../../device/device.service'; +import { SidebarComponent } from '../sidebar/sidebar.component'; + +@Component({ + selector: 'main-page', + templateUrl: './main-page.component.html', + styleUrls: ['./main-page.component.scss'] +}) +export class MainPageComponent implements OnInit { + static readonly invalidTokenCookieMessage = '[token cookie invalid]'; + + openFilterItem = { + 'entity': 'alerts', + 'key': 'status', + 'value': 'open' + }; + + warningIconFilter = JSON.stringify([ + { + 'entity': 'alerts', + 'key': 'severity', + 'value': 'warning' + }, + this.openFilterItem + ]); + + criticalIconFilter = JSON.stringify([ + { + 'entity': 'alerts', + 'key': 'severity', + 'value': 'critical' + }, + this.openFilterItem + ]); + + @ViewChild(SidebarComponent) + sidebar: SidebarComponent; + retracted = false; + logoutModalOpen = false; + username: string; + + warningCount = 0; + criticalCount = 0; + registeredDeviceIds = []; + + smallWindow = false; // Whether the window is too small that we need to shade + shrink the sidebar all the way + + constructor(private cookieService: CookieService, private deviceService: DeviceService, + private alertService: DeviceAlertService, private httpClient: HttpClient) { } + + static getTokenEmail(token: string): string { + if (isNullOrUndefined(token)) { + return MainPageComponent.invalidTokenCookieMessage; + } + + const jwtSplit = token.split('.'); + if (jwtSplit.length !== 3) { + return MainPageComponent.invalidTokenCookieMessage; + } + + try { + const claims = atob(jwtSplit[1]); + const parsedClaims = JSON.parse(claims); + if (!parsedClaims.hasOwnProperty('email')) { + return MainPageComponent.invalidTokenCookieMessage; + } + return parsedClaims.email; + } catch { + return MainPageComponent.invalidTokenCookieMessage; + } + } + + static getTokenExpiryTime(token: string): number { + if (isNullOrUndefined(token)) { + return null; + } + + const jwtSplit = token.split('.'); + if (jwtSplit.length !== 3) { + return null; + } + + try { + const claims = atob(jwtSplit[1]); + const parsedClaims = JSON.parse(claims); + if (!parsedClaims.hasOwnProperty('exp')) { + console.error('Couldn\'t find token expiration property'); + return null; + } + const expiresAt = parseInt(parsedClaims.exp, 10); + if (isNaN(expiresAt)) { + console.error('Token expiration time is not a number'); + return null; + } + return expiresAt - moment().unix(); + } catch { + return null; + } + } + + ngOnInit() { + if (this.cookieService.check('pure1-unplugged-token')) { + const token = this.cookieService.get('pure1-unplugged-token'); + this.username = MainPageComponent.getTokenEmail(token); + const expiresIn = MainPageComponent.getTokenExpiryTime(token); + if (!isNullOrUndefined(expiresIn)) { + console.debug('Token expires in ' + expiresIn + ' seconds'); + // If it's already expired, don't do anything (dunno how we got here in the first place anyways?) + if (expiresIn > 0) { + console.debug('Triggering expiration in ' + expiresIn + ' seconds'); + setTimeout(() => { + window.alert('Your session has expired. Please log in again.'); + window.location.reload(); + }, (expiresIn + 5) * 1000); // Reload a few seconds after it expires, just to make really sure it's expired + } + } + } else { + this.username = '[no token cookie]'; + } + + this.deviceService.list().subscribe(page => { + this.registeredDeviceIds = []; + page.response.forEach(device => { + this.registeredDeviceIds.push(device.id); + }); + }); + + this.alertService.list(new DeviceAlertQuery().withStatus('open')).subscribe(alerts => { + const deviceIDs = this.registeredDeviceIds; + this.warningCount = alerts.results.reduce(function(count: number, alert: DeviceAlert) { + // Only count still-registered devices (this just updates the icon a bit faster) + if (!deviceIDs.some(id => id === alert.ArrayID)) { + return count; + } + return count + (alert.Severity === 'warning' && alert.State === 'open' ? 1 : 0); + }, 0); + this.criticalCount = alerts.results.reduce(function(count: number, alert: DeviceAlert) { + // Only count still-registered devices (this just updates the icon a bit faster) + if (!deviceIDs.some(id => id === alert.ArrayID)) { + return count; + } + return count + (alert.Severity === 'critical' && alert.State === 'open' ? 1 : 0); + }, 0); + }); + } + + onSidebarToggleClick() { + this.sidebar.onSidebarToggleClick(); + } + + onSidebarToggled(retracted: boolean): void { + this.retracted = retracted; + } + + onUserClick() { + if (this.smallWindow && !this.retracted) { return; } // If the button is hidden behind the screen dimming, don't let it activate + + this.logoutModalOpen = !this.logoutModalOpen; + } + + pageClick(event) { + // If this isn't inside the user modal or the user display + if (event.target.closest('.logout-modal-wrapper, .topbar-item-user') === null) { + this.logoutModalOpen = false; // Close the logout modal + } + } + + @HostListener('window:resize', ['$event']) + onWindowResize(event) { + this.smallWindow = event.target.innerWidth < 768; + } + + logoutClick() { + const session = this.cookieService.get('pure1-unplugged-session'); + this.httpClient.delete('/auth/api-token', { + params: { + 'name': session + }, + responseType: 'text' + }).subscribe(null, null, () => { + this.cookieService.delete('pure1-unplugged-token', '/'); + this.cookieService.delete('pure1-unplugged-session', '/'); + window.location.reload(); + }); // Only handle success, not on error + } +} diff --git a/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.html b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.html new file mode 100644 index 00000000..77bea896 --- /dev/null +++ b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.html @@ -0,0 +1,19 @@ +
+
+ +
+
+ diff --git a/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.scss b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.scss new file mode 100644 index 00000000..3446e055 --- /dev/null +++ b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.scss @@ -0,0 +1,62 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.btn-toolbar { + display: flex; + position: relative; + height: 45px; + margin: 0px; + + .btn-group { + margin: 0px; + } + + .pagination-buttons { + .nav-pagination { + .count-range, .count-range:hover, .count-range:active { + height: fit-content; + line-height: 18px; + cursor: default; + + .current-count { + font-weight: 600; + } + + .total-count { + color: #8d8d8d; + } + } + + .btn > .pstg-action-icon { + display: inline-block; + position: absolute; + height: 10px; + width: 10px; + top: 8px; + left: 9px; + } + + .btn-disabled { + cursor: not-allowed; + opacity: .65; + } + + .btn-secondary { + background-color: #fff; + color: #454545; + border-color: #c5c5c5; + } + } + } +} diff --git a/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.spec.ts b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.spec.ts new file mode 100644 index 00000000..25b47e48 --- /dev/null +++ b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.spec.ts @@ -0,0 +1,216 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HttpClientModule } from '@angular/common/http'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { PaginationIndicatorComponent } from './pagination-indicator.component'; + +function getCurrentCountText(fixture: ComponentFixture): string { + const currentCountElem = fixture.elementRef.nativeElement.querySelectorAll('.current-count'); + if (currentCountElem.length === 0) { + return undefined; + } + return currentCountElem[0].innerHTML; +} + +function getTotalCountText(fixture: ComponentFixture): string { + const totalCountElem = fixture.elementRef.nativeElement.querySelectorAll('.total-count'); + if (totalCountElem.length === 0) { + return undefined; + } + return totalCountElem[0].innerHTML; +} + +function getButtonEnabled(fixture: ComponentFixture, index: number): boolean { + const buttons = fixture.elementRef.nativeElement.querySelectorAll('button'); + if (buttons.length !== 2) { + return undefined; + } + return !buttons[index].disabled; +} + +describe('PaginationIndicatorComponent', () => { + let component: PaginationIndicatorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PaginationIndicatorComponent ], + imports: [ + InlineSVGModule.forRoot(), + HttpClientModule + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PaginationIndicatorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should have both buttons disabled if length is set to 0', () => { + component.itemCount = 0; + // Set some other random values for testing + component.currentPage = 0; + component.itemsPerPage = 25; + fixture.detectChanges(); + const backwardEnabled = getButtonEnabled(fixture, 0); + expect(backwardEnabled).toBeDefined(); + expect(backwardEnabled).toBeFalsy(); + const forwardEnabled = getButtonEnabled(fixture, 1); + expect(forwardEnabled).toBeDefined(); + expect(forwardEnabled).toBeFalsy(); + }); + + it('should have both buttons disabled if length is set to the page size', () => { + component.itemCount = 25; + // Set some other random values for testing + component.currentPage = 0; + component.itemsPerPage = 25; + fixture.detectChanges(); + const backwardEnabled = getButtonEnabled(fixture, 0); + expect(backwardEnabled).toBeDefined(); + expect(backwardEnabled).toBeFalsy(); + const forwardEnabled = getButtonEnabled(fixture, 1); + expect(forwardEnabled).toBeDefined(); + expect(forwardEnabled).toBeFalsy(); + }); + + it('should have the forward button enabled if it can go forwards', () => { + component.itemCount = 26; // Just over one page + // Set some other random values for testing + component.currentPage = 0; + component.itemsPerPage = 25; + fixture.detectChanges(); + const backwardEnabled = getButtonEnabled(fixture, 0); + expect(backwardEnabled).toBeDefined(); + expect(backwardEnabled).toBeFalsy(); + const forwardEnabled = getButtonEnabled(fixture, 1); + expect(forwardEnabled).toBeDefined(); + expect(forwardEnabled).toBeTruthy(); + }); + + it('should have the backward button enabled if it can go backwards', () => { + component.itemCount = 26; // Just over one page + component.currentPage = 1; // So we can go back + component.itemsPerPage = 25; + fixture.detectChanges(); + const backwardEnabled = getButtonEnabled(fixture, 0); + expect(backwardEnabled).toBeDefined(); + expect(backwardEnabled).toBeTruthy(); + const forwardEnabled = getButtonEnabled(fixture, 1); + expect(forwardEnabled).toBeDefined(); + expect(forwardEnabled).toBeFalsy(); + }); + + it('should have the both buttons enabled if it can go both directions', () => { + component.itemCount = 51; // > 2 pages + component.currentPage = 1; + component.itemsPerPage = 25; + fixture.detectChanges(); + const backwardEnabled = getButtonEnabled(fixture, 0); + expect(backwardEnabled).toBeDefined(); + expect(backwardEnabled).toBeTruthy(); + const forwardEnabled = getButtonEnabled(fixture, 1); + expect(forwardEnabled).toBeDefined(); + expect(forwardEnabled).toBeTruthy(); + }); + + it('should show 0-0 of 0 if item count is set to 0', () => { + component.itemCount = 0; + // Set some other random values for testing + component.currentPage = 3; + component.itemsPerPage = 25; + fixture.detectChanges(); + const currentCountText = getCurrentCountText(fixture); + expect(currentCountText).toBeDefined(); + expect(currentCountText).toBe('0-0'); + const totalCountText = getTotalCountText(fixture); + expect(totalCountText).toBeDefined(); + expect(totalCountText).toBe(' of 0'); + }); + + it('should display the proper page values if it\'s at the beginning with an incomplete page', () => { + component.itemCount = 13; // Just over one page + component.currentPage = 0; + component.itemsPerPage = 25; + fixture.detectChanges(); + const currentCountText = getCurrentCountText(fixture); + expect(currentCountText).toBeDefined(); + expect(currentCountText).toBe('1-13'); + const totalCountText = getTotalCountText(fixture); + expect(totalCountText).toBeDefined(); + expect(totalCountText).toBe(' of 13'); + }); + + it('should display the proper page values if it\'s at the beginning', () => { + component.itemCount = 26; // Just over one page + component.currentPage = 0; + component.itemsPerPage = 25; + fixture.detectChanges(); + const currentCountText = getCurrentCountText(fixture); + expect(currentCountText).toBeDefined(); + expect(currentCountText).toBe('1-25'); + const totalCountText = getTotalCountText(fixture); + expect(totalCountText).toBeDefined(); + expect(totalCountText).toBe(' of 26'); + }); + + it('should display the proper page values if it\'s in the middle', () => { + component.itemCount = 51; // 3 pages worth + component.currentPage = 1; // 2nd page + component.itemsPerPage = 25; + fixture.detectChanges(); + const currentCountText = getCurrentCountText(fixture); + expect(currentCountText).toBeDefined(); + expect(currentCountText).toBe('26-50'); + const totalCountText = getTotalCountText(fixture); + expect(totalCountText).toBeDefined(); + expect(totalCountText).toBe(' of 51'); + }); + + it('should display the proper page values if it\'s at the end', () => { + component.itemCount = 27; // More than just over one page + component.currentPage = 1; + component.itemsPerPage = 25; + fixture.detectChanges(); + const currentCountText = getCurrentCountText(fixture); + expect(currentCountText).toBeDefined(); + expect(currentCountText).toBe('26-27'); + const totalCountText = getTotalCountText(fixture); + expect(totalCountText).toBeDefined(); + expect(totalCountText).toBe(' of 27'); + }); + + it('should display the proper page values if it\'s at the end with a 1 item page', () => { + component.itemCount = 26; + component.currentPage = 1; + component.itemsPerPage = 25; + fixture.detectChanges(); + const currentCountText = getCurrentCountText(fixture); + expect(currentCountText).toBeDefined(); + expect(currentCountText).toBe('26-26'); + const totalCountText = getTotalCountText(fixture); + expect(totalCountText).toBeDefined(); + expect(totalCountText).toBe(' of 26'); + }); +}); diff --git a/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.ts b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.ts new file mode 100644 index 00000000..fddfd2b6 --- /dev/null +++ b/gui/src/app/modules/core/components/pagination-indicator/pagination-indicator.component.ts @@ -0,0 +1,57 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; + +@Component({ + selector: 'pagination-indicator', + templateUrl: './pagination-indicator.component.html', + styleUrls: ['./pagination-indicator.component.scss'] +}) +export class PaginationIndicatorComponent implements OnInit { + @Input() itemCount = 0; + @Input() itemsPerPage = 0; + @Input() currentPage = 0; + + @Output() pageChange = new EventEmitter(); // emits new page index + + constructor() { + this.currentPage = 0; + } + + ngOnInit() { } + + getPageCount(): number { + return Math.ceil((this.itemCount / this.itemsPerPage)); + } + + getCurrentPageEndingIndex(): number { + if (this.currentPage >= this.getPageCount() - 1) { + return this.itemCount; + } else { + return (this.currentPage + 1) * this.itemsPerPage; + } + } + + pageClick(direction: number) { + const oldPage = this.currentPage; + // Add direction to current page, clamping to [0, pageCount) + this.currentPage = Math.min(Math.max(0, this.currentPage + direction), this.getPageCount() - 1); + + // Only emit in case of value change + if (this.currentPage !== oldPage) { + this.pageChange.emit(this.currentPage); + } + } +} diff --git a/gui/src/app/modules/core/components/sidebar/sidebar.component.html b/gui/src/app/modules/core/components/sidebar/sidebar.component.html new file mode 100644 index 00000000..e06967e3 --- /dev/null +++ b/gui/src/app/modules/core/components/sidebar/sidebar.component.html @@ -0,0 +1,51 @@ + + diff --git a/gui/src/app/modules/core/components/sidebar/sidebar.component.scss b/gui/src/app/modules/core/components/sidebar/sidebar.component.scss new file mode 100644 index 00000000..0c7c4529 --- /dev/null +++ b/gui/src/app/modules/core/components/sidebar/sidebar.component.scss @@ -0,0 +1,222 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#sidebar-wrapper { + position: fixed; + z-index: 1005; + top: 0; + height: 100vh; + left: 204px; + width: 204px; + margin-left: -204px; + background-color: #383838; + transition: width .5s ease, padding .5s ease, transform .5s ease; + overflow-x: visible; + + #sidebar-branding { + height: 55px; + background-color: #222222; + padding: 9px 2px 0 16px; + margin-bottom: 0; + cursor: pointer; + overflow: hidden; + white-space: nowrap; + transition: width .5s ease, padding-left .5s ease; + display: flex; + align-items: center; + flex-direction: horizontal; + + #sidebar-branding-logo { + width: 41px; + height: 35px; + margin-top: 1px; + margin-left: 0; + margin-bottom: 5px; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + + ::ng-deep svg { + .st0, .st1, .st2 { + display: inline; + fill: #fff; + } + } + } + + #sidebar-branding-text { + transform: scaleX(1); + margin-left: 8px; + display: inline; + flex-grow: 0; + flex-shrink: 0; + margin-bottom: 5px; + margin-top: 1px; + + ::ng-deep svg { + height: 28.77px; + } + } + + #sidebar-collapse-arrow { + margin-left: 43px; + margin-bottom: 5px; + height: 35px; + width: 4px; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + } + } + + .sidebar-item { + color: #8d8d8d; + width: 204px; + border-left: 3px solid transparent; + position: relative; + font-size: 14px; + cursor: pointer; + display: block; + transition: width .5s ease, color .3s ease, border-color .3s ease, background-color .3s ease; + + &.active { + color: #fff; + border-color: #fe5000; + background-color: #454545; + } + &:hover { + color: #fff; + } + } + + .sidebar-item-link { + display: block; + width: 204px; + color: inherit; + padding: 8px 10px; + } + + .sidebar-item-icon { + display: inline-block; + position: relative; + padding: 0 5px; + width: 25px; + margin: 3px 10px; + } + + .sidebar-item-text { + position: absolute; + left: 60px; + right: 10px; + font-size: 16px; + margin-left: 0; + height: 38px; + color: inherit; + overflow-x: hidden; + overflow-y: hidden; + } + + .sidebar-sub-item { + border-left: none; + font-size: 13px; + color: #8d8d8d; + padding: 0 2px 2px 60px; + cursor: pointer; + display: block; + white-space: nowrap; + position: relative; + overflow: hidden; + text-decoration: none; + + &:hover, &.active { + color: #fff; + } + } + + #sidebar-footer { + position: absolute; + bottom: 20px; + left: 25px; + font-size: 13px; + color: #8d8d8d; + overflow-wrap: break-word; + word-break: break-word; + padding-right: 25px; + min-width: 179px; + transition: margin .5s ease; + } + + &.retracted { + width: 70px; + margin-left: -204px; + + #sidebar-branding { + padding-left: 8px; + width: 70px; + + #sidebar-branding-text { + display: none; + + ::ng-deep svg { + width: 0px; + } + } + + #sidebar-collapse-arrow { + transform: scaleX(-1); + margin-left: 4px; + } + } + + &.smallWindow { + margin-left: -274px; + } + + .sidebar-item, .sidebar-item-link { + width: 70px; + } + + .sidebar-item:hover { + .dropdown-menu { + display: block; + transform: scaleX(1); /* Make visible with bounding box */ + } + } + + .sidebar-item-text { + color: transparent; + } + + .sidebar-expanded-only { + display: none; + } + + #sidebar-footer { + margin-left: -204px; + margin-right: 70px + } + } + + &:not(.retracted) .sidebar-collapsed-only { + display: none; + transform: scaleX(0); + } + + .sidebar-sub-item-group { + position: relative; + top: -8px; + padding-top: 5px; + padding-bottom: 3px; + } +} diff --git a/gui/src/app/modules/core/components/sidebar/sidebar.component.spec.ts b/gui/src/app/modules/core/components/sidebar/sidebar.component.spec.ts new file mode 100644 index 00000000..144e6320 --- /dev/null +++ b/gui/src/app/modules/core/components/sidebar/sidebar.component.spec.ts @@ -0,0 +1,54 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HttpClientModule } from '@angular/common/http'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { RouterTestingModule } from '@angular/router/testing'; +import { SidebarComponent } from './sidebar.component'; + +describe('SidebarComponent', () => { + let component: SidebarComponent; + let fixture: ComponentFixture; + let nativeElem: any = null; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SidebarComponent ], + imports: [ RouterTestingModule, HttpClientModule ], + schemas: [ NO_ERRORS_SCHEMA ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SidebarComponent); + component = fixture.componentInstance; + nativeElem = fixture.debugElement.nativeElement; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should start expanded', () => { + expect(nativeElem.querySelector('#sidebar-wrapper').classList.contains('retracted')).toBeFalsy(); + }); + + it('should have the correct number of tab elements', () => { + expect(nativeElem.querySelectorAll('#sidebar-wrapper .sidebar-item-link').length).toBe(SidebarComponent.tabs.length); + }); +}); diff --git a/gui/src/app/modules/core/components/sidebar/sidebar.component.ts b/gui/src/app/modules/core/components/sidebar/sidebar.component.ts new file mode 100644 index 00000000..2d17f41a --- /dev/null +++ b/gui/src/app/modules/core/components/sidebar/sidebar.component.ts @@ -0,0 +1,139 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { NavigationEnd, Router, RouterModule } from '@angular/router'; +import * as moment from 'moment'; +import { filter } from 'rxjs/operators'; +import { environment } from '../../../../../environments/environment'; +import { ISidebarTab } from '../../../../shared/interfaces/sidebar-tab'; +import { DeviceService } from '../../../device/device.service'; + +@Component({ + selector: 'sidebar', + templateUrl: './sidebar.component.html', + styleUrls: ['./sidebar.component.scss'], + providers: [ RouterModule ] +}) +export class SidebarComponent implements OnInit { + static tabs: ISidebarTab[] = [{ + title: 'Dashboard', + active: false, + link: '/dashboard', + icon: 'assets/images/nginclude/sidenav-dashboard.svg' + }, { + title: 'Arrays', + active: false, + link: '/arrays', + icon: 'assets/images/nginclude/sidenav-array.svg' + }, { + title: 'Analytics', + active: false, + link: '/analytics', + icon: 'assets/images/nginclude/sidenav-analytics.svg', + subTabs: [{ + title: 'Performance', + active: false, + link: '/analytics/performance' + }, { + title: 'Capacity', + active: false, + link: '/analytics/capacity' + }] + }, { + title: 'Messages', + active: false, + link: '/messages', + icon: 'assets/images/nginclude/sidenav-message.svg' + }, { + title: 'Troubleshooting', + active: false, + link: '/troubleshooting', + icon: 'assets/images/nginclude/sidenav-support.svg' + }]; + + connectedCount = 1; + totalCount = 1; + + retracted = false; + @Input() smallWindow = false; + @Output() toggled: EventEmitter = new EventEmitter(); + tabs: ISidebarTab[] = []; + activeTab: ISidebarTab = null; + appVersion = ''; + apiLastSeen: moment.Moment = null; + + constructor(private router: Router, private deviceService: DeviceService) { + this.tabs = SidebarComponent.tabs; + this.appVersion = environment.version; + } + + ngOnInit() { + this.updateTabActiveStates(); // Call once the first time since the router doesn't seem to fire this event + this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(val => { + this.updateTabActiveStates(); + }); + this.deviceService.list().subscribe(devices => { + this.totalCount = devices.response.length; + this.connectedCount = devices.response.reduce((count, device) => { + return count + (device.status === 'Connected' ? 1 : 0); + }, 0); + this.apiLastSeen = moment(); + }); + } + + isTabActive(tab: ISidebarTab): boolean { + return this.router.url.startsWith('/dash' + tab.link); // Comparing "startsWith" for the sake of matching subtabs + } + + updateTabActiveStates(): void { + this.tabs.forEach((tab: ISidebarTab) => { + tab.active = this.isTabActive(tab); + if (tab.active) { // This should always be only one tab, if it isn't something is dreadfully wrong + this.activeTab = tab; + } + if (tab.subTabs) { + tab.subTabs.forEach((subtab: ISidebarTab) => { + subtab.active = this.isTabActive(subtab); + if (subtab.active) { + this.activeTab = subtab; + } + }); + } + }); + } + + onSidebarToggleClick(): void { + this.retracted = !this.retracted; + this.toggled.emit(this.retracted); + } + + menuClick(): void { + // If the window is in the smaller state, make the sidebar retract again + if (this.smallWindow) { + this.retracted = true; + } + } + + getServerStatusString(): string { + if (this.apiLastSeen == null) { + return 'trying to connect'; + } + const diff = moment.duration(moment().diff(this.apiLastSeen, 'seconds'), 'seconds'); + if (diff.seconds() > 20) { // ~2 error periods worth + return 'disconnected'; + } + return 'connected'; + } +} diff --git a/gui/src/app/modules/core/core.module.ts b/gui/src/app/modules/core/core.module.ts new file mode 100644 index 00000000..8712a9b0 --- /dev/null +++ b/gui/src/app/modules/core/core.module.ts @@ -0,0 +1,39 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { AlertIndicatorComponent } from './components/alert-indicator/alert-indicator.component'; +import { DialComponent } from './components/dial/dial.component'; +import { PaginationIndicatorComponent } from './components/pagination-indicator/pagination-indicator.component'; + +@NgModule({ + declarations: [ + AlertIndicatorComponent, + DialComponent, + PaginationIndicatorComponent, + ], + imports: [ + InlineSVGModule.forRoot(), + CommonModule + ], + exports: [ + AlertIndicatorComponent, + DialComponent, + PaginationIndicatorComponent + ], + bootstrap: [] + }) + export class CoreModule { } diff --git a/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.html b/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.html new file mode 100644 index 00000000..6d2a12db --- /dev/null +++ b/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.html @@ -0,0 +1,6 @@ +
+ +
+ diff --git a/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.scss b/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.scss new file mode 100644 index 00000000..9eaaa1a5 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.scss @@ -0,0 +1,20 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +iframe { + border-style: none; + height: 100%; + width: 100%; +} + diff --git a/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.ts b/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.ts new file mode 100644 index 00000000..510b75c7 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/array-capacity/array-capacity.component.ts @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-array-capacity', + templateUrl: './array-capacity.component.html', + styleUrls: ['./array-capacity.component.scss'] +}) +export class ArrayCapacityComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.html b/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.html new file mode 100644 index 00000000..7a5d4c8e --- /dev/null +++ b/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.html @@ -0,0 +1,6 @@ +
+ +
+ diff --git a/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.scss b/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.scss new file mode 100644 index 00000000..3928dd11 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.scss @@ -0,0 +1,19 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +iframe { + border-style: none; + height: 100%; + width: 100%; +} diff --git a/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.ts b/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.ts new file mode 100644 index 00000000..e4a25f47 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/array-performance/array-performance.component.ts @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-array-performance', + templateUrl: './array-performance.component.html', + styleUrls: ['./array-performance.component.scss'] +}) +export class ArrayPerformanceComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.html b/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.html new file mode 100644 index 00000000..6404a6bd --- /dev/null +++ b/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.html @@ -0,0 +1,7 @@ +
+
+ +
+
+ + diff --git a/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.scss b/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.scss new file mode 100644 index 00000000..35c37fed --- /dev/null +++ b/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.scss @@ -0,0 +1,45 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.wrapper { + padding-left: 20px; + padding-right: 20px; + + .navbar { + padding: 0; + margin-left: -20px; + margin-right: -20px; + } + + .navbar-nav { + flex-direction: unset; + + .nav-item { + &:last-of-type { + .nav-link { + padding-right: 0px; + } + } + + .nav-link { + padding: 0 20px; + } + } + } + + .outlet-wrapper { + margin: 0px -20px; + } +} + diff --git a/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.ts b/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.ts new file mode 100644 index 00000000..6a4c5b75 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/capacity-dashboard/capacity-dashboard.component.ts @@ -0,0 +1,38 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; +import { filter } from 'rxjs/operators'; + +@Component({ + selector: 'capacity-dashboard', + templateUrl: './capacity-dashboard.component.html', + styleUrls: ['./capacity-dashboard.component.scss'] +}) +export class CapacityDashboardComponent implements OnInit { + + activatedRoute: string; + + constructor(private router: Router, private route: ActivatedRoute) { } + + ngOnInit() { + this.activatedRoute = this.route.firstChild.routeConfig.path; + this.router.events.pipe(filter(event => event instanceof NavigationEnd)) + .subscribe(_ => { + this.activatedRoute = this.route.firstChild.routeConfig.path; + }); + } + +} diff --git a/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.html b/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.html new file mode 100644 index 00000000..77c3aef4 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.html @@ -0,0 +1,6 @@ +
+ +
+ diff --git a/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.scss b/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.scss new file mode 100644 index 00000000..be2612cc --- /dev/null +++ b/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.scss @@ -0,0 +1,19 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +iframe { + border-style: none; + height: 100%; + width: 100%; + } diff --git a/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.ts b/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.ts new file mode 100644 index 00000000..c47b5ddf --- /dev/null +++ b/gui/src/app/modules/dashboard/components/filesystem-performance/filesystem-performance.component.ts @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-filesystem-performance', + templateUrl: './filesystem-performance.component.html', + styleUrls: ['./filesystem-performance.component.scss'] +}) +export class FilesystemPerformanceComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.html b/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.html new file mode 100644 index 00000000..555c0ef1 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.html @@ -0,0 +1,6 @@ +
+ +
+ diff --git a/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.scss b/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.scss new file mode 100644 index 00000000..271407ec --- /dev/null +++ b/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.scss @@ -0,0 +1,20 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +iframe { + border-style: none; + height: 100%; + width: 100%; + display: inline-block; +} diff --git a/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.ts b/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.ts new file mode 100644 index 00000000..a2df75df --- /dev/null +++ b/gui/src/app/modules/dashboard/components/main-dashboard/main-dashboard.component.ts @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'main-dashboard', + templateUrl: './main-dashboard.component.html', + styleUrls: ['./main-dashboard.component.scss'] +}) +export class MainDashboardComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.html b/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.html new file mode 100644 index 00000000..564c1622 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.html @@ -0,0 +1,25 @@ +
+ +
+ +
+
+ diff --git a/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.scss b/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.scss new file mode 100644 index 00000000..7bde2b99 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.scss @@ -0,0 +1,49 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.wrapper { + padding-left: 20px; + padding-right: 20px; + + .navbar { + padding: 0; + margin-left: -20px; + margin-right: -20px; + } + + .navbar-nav { + flex-direction: unset; + + .nav-item { + &:last-of-type { + .nav-link { + padding-right: 0px; + } + } + + .nav-link { + padding: 0 20px; + } + } + } + + .navbar-full { + z-index: 998; + } + + .outlet-wrapper { + margin: 0px -20px; + } +} + diff --git a/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.ts b/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.ts new file mode 100644 index 00000000..9daf54b6 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/performance-dashboard/performance-dashboard.component.ts @@ -0,0 +1,38 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; +import { filter } from 'rxjs/operators'; + +@Component({ + selector: 'performance-dashboard', + templateUrl: './performance-dashboard.component.html', + styleUrls: ['./performance-dashboard.component.scss'] +}) +export class PerformanceDashboardComponent implements OnInit { + + activatedRoute: string; + + constructor(private router: Router, private route: ActivatedRoute) { } + + ngOnInit() { + this.activatedRoute = this.route.firstChild.routeConfig.path; + this.router.events.pipe(filter(event => event instanceof NavigationEnd)) + .subscribe(_ => { + this.activatedRoute = this.route.firstChild.routeConfig.path; + }); + } + +} diff --git a/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.html b/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.html new file mode 100644 index 00000000..0691ad89 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.html @@ -0,0 +1,6 @@ +
+ +
+ diff --git a/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.scss b/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.scss new file mode 100644 index 00000000..3928dd11 --- /dev/null +++ b/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.scss @@ -0,0 +1,19 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +iframe { + border-style: none; + height: 100%; + width: 100%; +} diff --git a/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.ts b/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.ts new file mode 100644 index 00000000..549903ab --- /dev/null +++ b/gui/src/app/modules/dashboard/components/volume-performance/volume-performance.component.ts @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-volume-performance', + templateUrl: './volume-performance.component.html', + styleUrls: ['./volume-performance.component.scss'] +}) +export class VolumePerformanceComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/gui/src/app/modules/dashboard/dashboard.module.ts b/gui/src/app/modules/dashboard/dashboard.module.ts new file mode 100644 index 00000000..eabb3867 --- /dev/null +++ b/gui/src/app/modules/dashboard/dashboard.module.ts @@ -0,0 +1,47 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { RouterModule } from '@angular/router'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { CoreModule } from '../core/core.module'; +import { ArrayCapacityComponent } from './components/array-capacity/array-capacity.component'; +import { ArrayPerformanceComponent } from './components/array-performance/array-performance.component'; +import { CapacityDashboardComponent } from './components/capacity-dashboard/capacity-dashboard.component'; +import { FilesystemPerformanceComponent } from './components/filesystem-performance/filesystem-performance.component'; +import { MainDashboardComponent } from './components/main-dashboard/main-dashboard.component'; +import { PerformanceDashboardComponent } from './components/performance-dashboard/performance-dashboard.component'; +import { VolumePerformanceComponent } from './components/volume-performance/volume-performance.component'; + +@NgModule({ + imports: [ + CommonModule, + RouterModule, + CoreModule, + InlineSVGModule.forRoot(), + FormsModule + ], + declarations: [ + ArrayCapacityComponent, + ArrayPerformanceComponent, + CapacityDashboardComponent, + FilesystemPerformanceComponent, + MainDashboardComponent, + PerformanceDashboardComponent, + VolumePerformanceComponent + ] +}) +export class DashboardModule { } diff --git a/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.html b/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.html new file mode 100644 index 00000000..0cc8fcb5 --- /dev/null +++ b/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.html @@ -0,0 +1,74 @@ + +
+ + + + + + + + + + + + + + + + + + + +
+
+
+
+ Array +
+
+
+
+ +
+
+
+ Created +
+
+
+ Summary +
+
+
+
+ +
+
+
+ Status +
+
+
+ +
+
+
+ + + + {{alert.ArrayDisplayName}} + + + - + {{alert.Created | date: 'yyyy-MM-dd hh:mm:ss'}} + + + {{alert.Summary}} + + {{alert.State ? alert.State : 'unknown' }}
+
+ + diff --git a/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.scss b/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.scss new file mode 100644 index 00000000..e02a249a --- /dev/null +++ b/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.scss @@ -0,0 +1,95 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +pagination-indicator { + position: absolute; + top: 15px; + right: 20px; +} + +.table-fixed-header-container { + height: calc(100vh - 55px - 10px - 60px); + top: 60px; + overflow: visible; + margin: 0px 20px; + + .table { + width: 100%; + + .column-headings { + height: 28px; + } + + td { + padding: 5px 20px; + } + + .icon-column { + width: 40px; + flex-grow: 0; + text-overflow: clip; + text-align: right; + cursor: pointer; + } + + .column-group-title { + cursor: pointer; + } + + .message-row { + cursor: pointer; + + .icon-column-icon-cell { + height: 30px; + flex-grow: 0; + padding: 5px 12px; + overflow-y: hidden; + text-overflow: clip; + } + } + + .manual-sort { + fill: #fb5000; + display: inline-block; + width: 8.58px; + } + + .manual-sort.st-sort-none { + transform: scaleY(0); + } + + .manual-sort.st-sort-ascent { + transform: scaleY(-1); + vertical-align: top; + } + + .manual-sort.st-sort-descent { + transform: scaleY(1); + vertical-align: bottom; + } + + .custom-text { + height: 28px; + top: 0px; + } + + #status-select { + height: 28px; + } + } +} + + + + diff --git a/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.ts b/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.ts new file mode 100644 index 00000000..0cb63f58 --- /dev/null +++ b/gui/src/app/modules/device-alert/components/alerts-view/alerts-view.component.ts @@ -0,0 +1,251 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit, ViewChild } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { DeviceAlert } from '../../../../shared/models/device-alert'; +import { DeviceAlertQuery } from '../../../../shared/models/device-alert-query'; +import { PaginationIndicatorComponent } from '../../../core/components/pagination-indicator/pagination-indicator.component'; +import { DeviceAlertService } from '../../device-alert.service'; + +@Component({ + selector: 'alerts-view', + templateUrl: './alerts-view.component.html', + styleUrls: ['./alerts-view.component.scss'], + providers: [ NgbTooltip ] +}) +export class AlertsViewComponent implements OnInit { + @ViewChild(PaginationIndicatorComponent) pagination: PaginationIndicatorComponent; + readonly PAGE_SIZE: number = 50; // Constant + + alerts: DeviceAlert[] = []; + alertCancelSubject: Subject; + + states: string[]; + + filter: any[]; + sort: string; + sortDesc: boolean; + + deviceQuery: string; + summaryQuery: string; + statusQuery: string; + severityQuery: string; + + constructor(private alertService: DeviceAlertService, private route: ActivatedRoute, private router: Router) { } + + ngOnInit() { + this.reconnectAlertService(); + + this.route.queryParams.subscribe(params => { + if (params['filter']) { + this.filter = JSON.parse(params['filter']); + } else { + this.filter = []; + } + + if (params['sort']) { + this.sortDesc = params['sort'].endsWith('-'); + if (this.sortDesc) { + this.sort = params['sort'].substring(0, params['sort'].length - 1); + } else { + this.sort = params['sort']; + } + } else { + this.sort = ''; + } + + if (params['page']) { + this.pagination.currentPage = parseInt(params['page'], 10); + } else { + this.pagination.currentPage = 0; + } + + // Default to 'all' if there's no status parameter + this.statusQuery = 'all'; + + // Set model variables for the text boxes + this.filter.forEach(filter => { + if (filter.entity !== 'alerts') { return; } + + if (filter.key === 'array') { this.deviceQuery = filter.value; } + if (filter.key === 'summary') { this.summaryQuery = filter.value; } + if (filter.key === 'status') { this.statusQuery = filter.value; } + if (filter.key === 'severity') { this.severityQuery = filter.value; } + }); + + this.reconnectAlertService(); + }); + } + + // Makes a DeviceAlertQuery object from the current parameters + constructAlertQuery(): DeviceAlertQuery { + const query = new DeviceAlertQuery(); + if (this.deviceQuery && this.deviceQuery !== '') { + query.withDeviceName(this.deviceQuery.toLowerCase()); // Elastic is set up to search with lowercase + } + if (this.summaryQuery && this.summaryQuery !== '') { + query.withAlertSummary(this.summaryQuery.toLowerCase()); // Elastic is set up to search with lowercase + } + // ignore "all", since that's basically the same as not having a query for it at all + if (this.statusQuery && this.statusQuery !== '' && this.statusQuery !== 'all') { + query.withStatus(this.statusQuery); + } + if (this.severityQuery && this.severityQuery !== '') { + query.withSeverity(this.severityQuery); + } + query.withPageSize(this.PAGE_SIZE); + query.withPage(this.pagination.currentPage); + query.withSort(this.sort, this.sortDesc ? 'desc' : 'asc'); + + return query; + } + + // Stops the existing connection, then makes a new one + reconnectAlertService() { + if (this.alertCancelSubject) { + this.alertCancelSubject.next(); + } + + this.alertCancelSubject = new Subject(); + + this.alertService.list(this.constructAlertQuery()).pipe(takeUntil(this.alertCancelSubject)).subscribe(alerts => { + this.alerts = alerts.results; + this.pagination.itemCount = alerts.totalHits; + this.states = alerts.states; + }); + } + + // Renavigates to the messages page, applying the filter, sort, and current page + renavigate(clear: boolean): void { + // Clean up the filters before renavigating: while this doesn't ensure clean filters *all* the time (user-entered URLs could be dirty), + // it at least makes sure that when we change them programmatically they end up clean. + this.removeImproperFilters(); + const queryParams = {}; + if (this.filter.length > 0) { + queryParams['filter'] = JSON.stringify(this.filter); + } + if (this.sort) { + queryParams['sort'] = this.sort; + if (this.sortDesc) { + queryParams['sort'] += '-'; + } + } + if (this.pagination.currentPage !== 0) { + queryParams['page'] = this.pagination.currentPage; + } + const urlWithoutParams = this.router.parseUrl(this.router.url).root.children['primary'].segments.map(it => '/' + it.path).join(''); + this.router.navigate([urlWithoutParams], { queryParams: queryParams}); + if (clear) { + this.alerts = []; + } + } + + // Sets (creates/overwrites) the value for a key in the filter + setFilterKeyValue(key: string, value: string): void { + let keyExists = false; + this.filter.forEach(filter => { + if (filter.entity !== 'alerts' || filter.key !== key) { return; } + + filter.value = value; + keyExists = true; + }); + if (!keyExists) { + this.filter.push({ entity: 'alerts', key: key, value: value }); + } + } + + // Removes filters that are missing a field or have empty fields + removeImproperFilters(): void { + this.filter = this.filter.filter(f => f.hasOwnProperty('entity') && f.entity !== '' && + f.hasOwnProperty('key') && f.key !== '' && + f.hasOwnProperty('value') && f.value !== ''); + } + + pageClick(direction: number): void { + this.pagination.currentPage += direction; + if (this.pagination.currentPage < 0) { this.pagination.currentPage = 0; } + + this.renavigate(true); + } + + sortClick(param: string): void { + // If we're already sorting this one, invert it + if (this.sort === param) { + this.sortDesc = !this.sortDesc; + } else { + this.sort = param; + this.sortDesc = false; + } + this.renavigate(true); + } + + onDeviceNameInputChange(event): void { + this.deviceQuery = event; + this.setFilterKeyValue('array', this.deviceQuery); + this.pagination.currentPage = 0; + this.renavigate(false); + } + + onSummaryInputChange(event): void { + this.summaryQuery = event; + this.setFilterKeyValue('summary', this.summaryQuery); + this.pagination.currentPage = 0; + this.renavigate(false); + } + + onStatusInputChange(event): void { + this.statusQuery = event; + if (this.statusQuery === 'all') { + // Remove the status query altogether + this.filter = this.filter.filter(filter => !(filter.entity === 'alerts' && filter.key === 'status')); + } else { + this.setFilterKeyValue('status', this.statusQuery); + } + this.pagination.currentPage = 0; + this.renavigate(false); + } + + getMaxPageCount(): number { + return Math.floor(this.pagination.itemCount / this.PAGE_SIZE); + } + + getCurrentPageEndingIndex(): number { + if (this.pagination.currentPage >= this.getMaxPageCount()) { + return this.pagination.itemCount; + } else { + return (this.pagination.currentPage + 1) * this.PAGE_SIZE; + } + } + + // Gets the style to apply to a column header given the parameter key + getSortStyle(param: string): string { + if (!this.sort) { return 'st-sort-none'; } + if (this.sort !== param) { return 'st-sort-none'; } + + // This is the parameter being sorted, now which direction? + return this.sortDesc ? 'st-sort-descent' : 'st-sort-ascent'; + } + + trackByState(index, state: string) { + return state; + } + + trackByAlertAndDeviceID(index, alert: DeviceAlert) { + return alert.ArrayID + alert.AlertID; + } +} diff --git a/gui/src/app/modules/device-alert/device-alert.module.ts b/gui/src/app/modules/device-alert/device-alert.module.ts new file mode 100644 index 00000000..7f1405ad --- /dev/null +++ b/gui/src/app/modules/device-alert/device-alert.module.ts @@ -0,0 +1,42 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; +import { NgbModalModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { CoreModule } from '../core/core.module'; +import { AlertsViewComponent } from './components/alerts-view/alerts-view.component'; + +@NgModule({ + declarations: [ + AlertsViewComponent + ], + imports: [ + BrowserModule, + InlineSVGModule.forRoot(), + NgbModalModule.forRoot(), + FormsModule, + ReactiveFormsModule, + NgbTooltipModule, + CoreModule, + CommonModule, + RouterModule + ], + bootstrap: [] + }) + export class DeviceAlertModule { } diff --git a/gui/src/app/modules/device-alert/device-alert.service.ts b/gui/src/app/modules/device-alert/device-alert.service.ts new file mode 100644 index 00000000..1ef75506 --- /dev/null +++ b/gui/src/app/modules/device-alert/device-alert.service.ts @@ -0,0 +1,117 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import * as moment from 'moment'; +import { Observable, timer } from 'rxjs'; +import { delayWhen, map, repeatWhen, retryWhen } from 'rxjs/operators'; +import { DeviceAlert } from '../../shared/models/device-alert'; +import { DeviceAlertQuery } from '../../shared/models/device-alert-query'; +import { DeviceAlertResult } from '../../shared/models/device-alert-result'; + +@Injectable({ + providedIn: 'root' +}) +export class DeviceAlertService { + ELASTIC_ADDRESS = '/elasticsearch'; + + ALERTS_ENDPOINT = '/pure-alerts/alerts/_search'; + ALERTS_FILTER_PATH = 'hits.hits._source,hits.total,aggregations.all.states.buckets.key'; + + constructor(private http: HttpClient) { } + + convertRawAlertToClass(rawAlert: any): DeviceAlert { + const toReturn = new DeviceAlert(); + + toReturn.AlertID = rawAlert['AlertID']; + toReturn.Code = rawAlert['Code']; + toReturn.Created = rawAlert['Created'] === 0 ? null : moment.unix(rawAlert['Created']); + toReturn.ArrayHostname = rawAlert['ArrayHostname']; + toReturn.ArrayID = rawAlert['ArrayID']; + toReturn.ArrayName = rawAlert['ArrayName']; + toReturn.ArrayDisplayName = rawAlert['ArrayDisplayName']; + toReturn.Severity = rawAlert['Severity']; + toReturn.SeverityIndex = rawAlert['SeverityIndex']; + toReturn.State = rawAlert['State']; + toReturn.Summary = rawAlert['Summary']; + + return toReturn; + } + + list(query: DeviceAlertQuery = new DeviceAlertQuery()): Observable { + const requestObj = query.generateRequestObject(); + // Add an aggregation by state, so we can find whcih + requestObj['aggs'] = { + 'all': { + 'global': {}, + 'aggs': { + 'states': { + 'terms': { + 'field': 'State' + } + } + } + } + }; + + return this.http.post(this.ELASTIC_ADDRESS + this.ALERTS_ENDPOINT + '?filter_path=' + this.ALERTS_FILTER_PATH, + JSON.stringify(requestObj), + { headers: { 'Content-Type': 'application/json'}}) + .pipe(map(rawResponse => { + // If we're missing fields, just set up empty default objects so that the rest of the flow works right + if (!('hits' in rawResponse) || + !('hits' in rawResponse['hits'])) { + rawResponse['hits']['hits'] = []; + } + if (!('aggregations' in rawResponse) || + !('all' in rawResponse['aggregations']) || + !('states' in rawResponse['aggregations']['all']) || + !('buckets' in rawResponse['aggregations']['all']['states'])) { + rawResponse['aggregations'] = { + 'all': { + 'states': { + 'buckets': [] + } + } + }; + } + + return rawResponse; + })) + .pipe(map(rawHits => { + const alerts = []; + + rawHits['hits']['hits'].forEach(hit => { + alerts.push(this.convertRawAlertToClass(hit['_source'])); + }); + + const states = []; + rawHits['aggregations']['all']['states']['buckets'].forEach(bucket => { + states.push(bucket['key']); + }); + + return new DeviceAlertResult(alerts, rawHits['hits']['total'], states); + })) + .pipe(repeatWhen(delayWhen(() => { + // Repeatedly poke the alert service (but only every 15 seconds because we really don't need this to update often) + console.debug('Alert list fetch successful.'); + return timer(15000); + })), retryWhen(delayWhen(() => { + // Repeatedly poke the alert service, slower since we're having a hard time talking to it. + console.log('Alert list fetch unsuccessful, retrying.'); + return timer(30000); + }))); + } +} diff --git a/gui/src/app/modules/device/components/device-card/device-card.component.html b/gui/src/app/modules/device/components/device-card/device-card.component.html new file mode 100644 index 00000000..0bdce789 --- /dev/null +++ b/gui/src/app/modules/device/components/device-card/device-card.component.html @@ -0,0 +1,118 @@ +
+
+
+
+
+
+
+ + +
+
+
+
+
{{device?.model}}
+
{{device?.version}}
+
+
+
+
+ Connecting... +
+
+
+
+
+ +
+
{{dataPercentFullRounded}}
+
{{dataUsageString}}
+
+
+
+
{{latestMetric?.DataReduction | number:'1.1-1'}} to 1
+
Data Reduction
+
+
+
+
+
+ Latency
(ms)
+
+
+
+
R
+
{{latestMetric?.ReadLatency / 1000 | number:'1.2-2'}}
+
+
+
+
W
+
{{latestMetric?.WriteLatency / 1000 | number:'1.2-2'}}
+
+
+
+
O
+
{{latestMetric?.OtherLatency / 1000 | number:'1.2-2'}}
+
+
+
+
+
+
+
IOPS
+
{{iopsString}}
+
{{iopsSuffix}}
+
+
+
+
Bandwidth
+
{{bandwidthString}}
+
{{bandwidthSuffix}}
+
+
+
+
+
+
+ Connected, waiting for metrics data...

+ This may take a little while (up to ~30 seconds) +
+
+
+
+
+
+ {{device.status}}

+ Last seen {{getAsOfText()}} +
+
+
+
+
+ +
{{alerts.length}} open alert{{alerts.length === 1 ? '' : 's'}}
+
+
+ +
{{alert.Summary}}
+
{{alert.Created | date: 'yyyy-MM-dd hh:mm:ss'}}
+
+
+
+ Unregister Array +
+
+
+
+ diff --git a/gui/src/app/modules/device/components/device-card/device-card.component.scss b/gui/src/app/modules/device/components/device-card/device-card.component.scss new file mode 100644 index 00000000..7eb20351 --- /dev/null +++ b/gui/src/app/modules/device/components/device-card/device-card.component.scss @@ -0,0 +1,441 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +$delete-button-height: 50px; + +.card-div { + white-space: nowrap; + width: 285px; + height: 350px; + margin: 0 7px 11px; + text-align: center; + + .card-flip { + height: 100%; + width: 100%; + position: relative; + perspective: 1000; + + .card { + border-radius: 4px; + border: 1px solid #c5c5c5; + display: block; + position: relative; + background-color: #fff; + + .array-disconnected-message { + font-weight: 500; + color: #8d8d8d; + font-size: 12px; + margin-top: 100px; + margin-left: 5px; + margin-right: 5px; + text-align: center; + + .array-disconnected-icon { + height: 30px; + width: 45px; + display: inline-block; + } + } + + .card-array-stats { + margin: 20px; + display: flex; + justify-content: space-between; + align-items: center; + + .card-array-stats-capacity { + position: relative; + display: inline-block; + height: 125px; + width: 125px; + color: #454545; + + .card-capacity { + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + padding-top: 30px; + + .card-capacity-perc { + font-weight: 600; + font-size: 36px; + position: relative; + left: 3px; + box-sizing: inherit; + } + + .card-capacity-perc::after { + content: '%'; + font-size: 20px; + box-sizing: inherit; + } + + .card-capacity-str { + color: #8d8d8d; + font-size: 11px; + font-weight: 500; + position: relative; + top: -13px; + } + } + } + + .card-array-stats-dr { + display: inline-block; + width: 110px; + + .data-reduction-ratio { + font-size: 24px; + font-weight: 600; + position: relative; + top: 4px; + } + + .data-reduction-string { + font-weight: 600; + color: #8d8d8d; + position: relative; + bottom: 4px; + } + } + } + + .card-perf-wrapper { + margin: 0 10px; + + .card-perf-stats { + border-radius: 4px; + margin-bottom: 5px; + box-sizing: border-box; + + .card-perf-stats.latency { + background-color: #e6e6e6; + min-height: 53px; + } + + .card-perf-title { + position: relative; + top: 2px; + margin-bottom: -4px; + font-size: 14px; + font-weight: 600; + color: #8d8d8d; + text-align: center; + + .perf-unit { + font-weight: 400; + font-size: 12px; + color: #8d8d8d; + display: inline-block; + width: 0; + } + } + + .card-perf-metrics { + display: flex; + justify-content: space-evenly; + + .card-perf-read, .card-perf-write, .card-perf-other { + flex-grow: 1; + + .perf-type { + color: #8d8d8d; + font-weight: 600; + width: 12px; + text-align: right; + display: inline-block; + } + + .perf-value { + font-size: 24px; + font-weight: 600; + color: #454545; + width: 62px; + text-align: right; + padding-right: 2px; + display: inline-block; + } + + .perf-unit { + color: #454545; + font-weight: 600; + width: 28px; + text-align: left; + display: inline-block; + } + } + + .card-perf-divider { + width: 1px; + height: 15px; + background-color: #c5c5c5; + margin-top: auto; + margin-bottom: 8px; + flex-grow: 0; + } + } + } + + .card-perf-stats.latency { + background-color: #e6e6e6; + min-height: 53px; + } + + .card-perf-title { + position: relative; + top: 2px; + margin-bottom: -4px; + font-size: 14px; + font-weight: 600; + color: #8d8d8d; + text-align: center; + + .perf-unit { + font-weight: 400; + font-size: 12px; + color: #8d8d8d; + display: inline-block; + width: 0; + } + } + } + } + + .card-back, .card-front { + position: absolute; + height: 100%; + width: 100%; + top: 0; + left: 0; + overflow: hidden; + backface-visibility: hidden; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -o-backface-visibility: hidden; + transition: transform .6s ease; + transform-style: preserve-3d; + transition: 0.6s; + transform-style: preserve-3d; + -webkit-transition: 0.6s; + -webkit-transform-style: preserve-3d; + -moz-transition: 0.6s; + -moz-transform-style: preserve-3d; + -o-transition: 0.6s; + -o-transform-style: preserve-3d; + -ms-transition: 0.6s; + -ms-transform-style: preserve-3d; + } + + .card-front { + z-index: 2; + background-color: #fff; + + .card-header { + background-color: #f5f5f5; + + .card-array-title { + text-align: center; + padding: 0; + font-weight: 600; + font-size: 17px; + text-overflow: ellipsis; + overflow: hidden; + + a { + color: inherit; + } + } + + alert-indicator { + width: 20px; + height: 20px; + line-height: 22px; + font-size: 16px; + cursor: pointer; + text-align: center; + position: relative; + display: block; + } + + .card-alert-indicator { + position: absolute; + z-index: 1; + right: 10px; + top: 10px; + } + + .card-tag-icon { + width: 20px; + height: 20px; + line-height: 22px; + font-size: 16px; + cursor: pointer; + text-align: center; + position: absolute; + z-index: 1; + left: 10px; + top: 10px; + display: block; + fill: #dddddd; + } + } + } + + .card-back { + margin-top: 0; + transform: rotateY(-180deg); + background-color: #454545; + border-color: #454545; + border-radius: 4px; + + .card-header { + background: transparent; + color: white; + border-bottom-color: transparent; + + .card-array-title { + text-align: center; + padding: 0; + font-weight: 600; + font-size: 17px; + text-overflow: ellipsis; + overflow: hidden; + + a { + color: inherit; + } + } + + alert-indicator { + width: 20px; + height: 20px; + line-height: 22px; + font-size: 16px; + cursor: pointer; + text-align: center; + position: relative; + display: block; + } + + .card-alert-indicator { + position: absolute; + z-index: 1; + right: 10px; + top: 10px; + } + } + + .card-alert-summary { + color: white; + font-size: 14px; + text-align: left; + margin: 10px 0 10px 42px; + } + + .array-alert { + color: white; + position: relative; + margin: 0 17px 8px 42px; + padding-bottom: 8px; + text-align: left; + + alert-indicator { + position: absolute; + left: -30px; + top: 2px; + right: auto; + } + + .alert-event { + font-size: 14px; + text-overflow: ellipsis; + overflow: hidden; + } + + .alert-opened { + font-size: 10px; + color: #8d8d8d; + } + } + + .slimScrollDiv { + overflow-y: auto; + position: relative; + width: auto; + height: calc(265px - #{$delete-button-height}); + } + + .container-fluid { + margin-left: auto; + margin-right: auto; + padding-right: 10px; + padding-left: 10px; + + .row { + margin-right: -10px; + margin-left: -10px; + display: flex; + flex-wrap: wrap; + + .col-xs-6 { + flex: 0 0 50%; + max-width: 50%; + } + } + } + + .device-delete-button { + height: $delete-button-height; + border-top: 1px solid #5e5e5e; + margin-top: -7px; + cursor: pointer; + line-height: $delete-button-height; + color: #fff; + font-size: 14px; + + &:hover { + background-color: #515151; + } + } + } + } + + .small-card .array-info { + color: #454545; + height: 24px; + line-height: 24px; + border-bottom: solid 1px #eaeaea; + } +} + +.card-div.flip { + .card-flip { + .card-front { + transform: rotateY(180deg); + } + + .card-back { + transform: rotateY(0deg); + } + } +} + +.row { + margin-right: 0px; + margin-left: 0px; +} diff --git a/gui/src/app/modules/device/components/device-card/device-card.component.spec.ts b/gui/src/app/modules/device/components/device-card/device-card.component.spec.ts new file mode 100644 index 00000000..5c745698 --- /dev/null +++ b/gui/src/app/modules/device/components/device-card/device-card.component.spec.ts @@ -0,0 +1,63 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpClientModule } from '@angular/common/http'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { NgSlimScrollModule } from 'ngx-slimscroll'; +import { CoreModule } from '../../../core/core.module'; +import { DeviceCardComponent } from './device-card.component'; + +describe('DeviceCardComponent', () => { + // Shared test components + // All should be set in beforeEach() + let fixture: ComponentFixture = null; + let component: any = null; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + DeviceCardComponent, + ], + imports: [ + InlineSVGModule.forRoot(), + HttpClientModule, + NgbModule.forRoot(), + CoreModule, + NgSlimScrollModule + ], + }).compileComponents(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(DeviceCardComponent); + component = fixture.debugElement.componentInstance; + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + describe('PercentageDisplay', () => { + it('should process low decimals properly', async () => { + expect(DeviceCardComponent.getRoundedPercentage(0.05123)).toBe(5); + }); + it('should process middle decimals properly', async () => { + expect(DeviceCardComponent.getRoundedPercentage(0.055)).toBe(5); + }); + it('should process high decimals properly', async () => { + expect(DeviceCardComponent.getRoundedPercentage(0.05987)).toBe(5); + }); + }); +}); diff --git a/gui/src/app/modules/device/components/device-card/device-card.component.ts b/gui/src/app/modules/device/components/device-card/device-card.component.ts new file mode 100644 index 00000000..966c3387 --- /dev/null +++ b/gui/src/app/modules/device/components/device-card/device-card.component.ts @@ -0,0 +1,319 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * This component is a "card" for a storage device. It should display the name and other + * relevant information. + */ +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import * as moment from 'moment'; +import { ISlimScrollOptions } from 'ngx-slimscroll'; +import { of, Subject } from 'rxjs'; +import { catchError, takeUntil } from 'rxjs/operators'; +import { DeviceAlert } from '../../../../shared/models/device-alert'; +import { DeviceMetric } from '../../../../shared/models/device-metric'; +import { DeviceTag } from '../../../../shared/models/device-tag'; +import { StorageDevice } from '../../../../shared/models/storage-device'; +import { DeviceMetricsService } from '../../../../shared/services/device-metrics.service'; +import { DeviceTagsService } from '../../../../shared/services/device-tags.service'; +import { DeviceService } from '../../device.service'; +import { DeviceDeleteModalComponent } from '../device-delete-modal/device-delete-modal.component'; +import { TagEditModalComponent } from '../tag-edit-modal/tag-edit-modal.component'; + +@Component({ + selector: 'device-card', + templateUrl: './device-card.component.html', + styleUrls: ['./device-card.component.scss'] +}) +export class DeviceCardComponent implements OnInit, OnDestroy { + flipped = false; + metricsStopService: Subject; + + @Input() device: StorageDevice; + @Input() tags: Map>; + @Input() alerts: DeviceAlert[]; + + latestMetric: DeviceMetric = null; + dataPercentFull = 0.0; + dataPercentFullRounded = 0; + dataUsageString = ''; + dataStatus: 'ok' | 'warning' | 'critical' = 'ok'; + iopsString = ''; + iopsSuffix = ''; + bandwidthString = ''; + bandwidthSuffix = ''; + + scrollOptions: ISlimScrollOptions = { + alwaysVisible: true, + position: 'right', + + gridOpacity: '0.2', + gridBackground: '#333333', + gridWidth: '7', + gridBorderRadius: '7', + gridMargin: '0', + + barOpacity: '0.4', + barBackground: '#e6e6e6', + barWidth: '7', + barBorderRadius: '7', + barMargin: '0', + }; + + static getRoundedPercentage(decimalFull: number): number { + return Math.floor(decimalFull * 100); + } + + constructor(private deviceService: DeviceService, private modalService: NgbModal, private tagsService: DeviceTagsService, + private metricsService: DeviceMetricsService) { } + + ngOnInit() { + console.debug(`Initializing device display for device "${this.device.name}"`); + this.metricsStopService = new Subject(); + this.metricsService.getLatestMetric(this.device.id).pipe(takeUntil(this.metricsStopService)).subscribe(metric => { + this.processMetric(metric); + }); + } + + processMetric(metric: DeviceMetric) { + this.latestMetric = metric; + this.dataPercentFull = metric.PercentFull; + this.dataPercentFullRounded = DeviceCardComponent.getRoundedPercentage(this.dataPercentFull); + if (this.dataPercentFull >= 1.0) { + this.dataStatus = 'critical'; + } else if (this.dataPercentFull >= 0.9) { + this.dataStatus = 'warning'; + } else { + this.dataStatus = 'ok'; + } + this.createTotalSpaceString(); + this.createIOPSStringAndSuffix(); + this.createBandwidthStringAndSuffix(); + } + + ngOnDestroy(): void { + if (this.metricsStopService) { + this.metricsStopService.next(); + } + } + + createTotalSpaceString() { + const totalSpacePower = this.getDiskSuffixPower(this.latestMetric.TotalSpace); + const usedReduced = this.latestMetric.UsedSpace / Math.pow(1024, totalSpacePower); + const totalReduced = this.latestMetric.TotalSpace / Math.pow(1024, totalSpacePower); + this.dataUsageString = `${usedReduced.toFixed(1)} / ${totalReduced.toFixed(1)} ${this.getSuffix(totalSpacePower)}`; + } + + createIOPSStringAndSuffix() { + const iops = this.latestMetric.ReadIOPS + this.latestMetric.WriteIOPS; + const iopsSuffixPower = this.getNumberSuffixPower(iops); + const convertedIOPS = iops / Math.pow(1000, iopsSuffixPower); + + if (iopsSuffixPower > 0) { + this.iopsString = convertedIOPS.toFixed(1); + } else { + this.iopsString = convertedIOPS.toFixed(0); + } + this.iopsSuffix = this.getSuffix(iopsSuffixPower); + } + + createBandwidthStringAndSuffix() { + const bandwidth = this.latestMetric.WriteBandwidth + this.latestMetric.ReadBandwidth; + const bandwidthSuffixPower = this.getDiskSuffixPower(bandwidth); + const convertedBandwidth = bandwidth / Math.pow(1024, bandwidthSuffixPower); + + // Bandwidth always has one decimal + this.bandwidthString = convertedBandwidth.toFixed(1); + this.bandwidthSuffix = this.getSuffix(bandwidthSuffixPower) + 'B/s'; + } + + getNumberSuffixPower(iops: number): number { + if (iops === 0) { return 0; } + + // Use change of base formula to calculate log base 1000 + // Base 1000 here since this is IOPS, a number, not a disk space + return Math.floor(Math.log(iops) / Math.log(1000)); + } + + getDiskSuffixPower(size: number): number { + if (size === 0) { return 0; } // This is almost certainly never gonna happen, but just in case + + // Use change of base formula to calculate log base 1024 + // Base 1024 here because it's a disk space unit, not a generic number + return Math.floor(Math.log(size) / Math.log(1024)); + } + + getSuffix(power: number): string { + switch (power) { + case 5: + return 'P'; + case 4: + return 'T'; + case 3: + return 'G'; + case 2: + return 'M'; + case 1: + return 'K'; + case 0: + return ''; + } + } + + // Should never return null + safeGetTag(ns: string, key: string): string { + if (this.tags && this.tags.has(ns) && this.tags.get(ns).has(key)) { + return this.tags.get(ns).get(key); + } + return ''; + } + + isFlashBlade(): boolean { + return this.device.device_type === 'FlashBlade'; + } + + getTags(): DeviceTag[] { + if (!this.tags) { return []; } + + const toReturn = []; + + this.tags.forEach((keyValue: Map, namespace: string) => { + keyValue.forEach((value: string, key: string) => { + toReturn.push({ namespace: namespace, key: key, value: value }); + }); + }); + + return toReturn; + } + + getAsOfText(): string { + const parsed = moment(this.device._as_of, ['YYYY-MM-DD[T]HH:mm:ss[Z]', 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]']); + if (parsed.year() === 1) { + // This is a zero date + return 'never'; + } + + const now = moment(); + + // Longer than a month, just return the date + // Reasoning: this way the user will focus more on the date and that + // "this was a long time ago", instead of getting bogged down looking + // at an actual time (and is additionally cleaner). Contrast this with + // something a bit more recent, where they may still be looking at logs + // and determining what happened and a time would be useful to see more easily. + if (now.diff(parsed, 'months', false) >= 1) { + return parsed.format('DD MMM YYYY'); + } + + return parsed.format('DD MMM YYYY HH:mm:ss'); + } + + onFlipClick(): void { + this.flipped = !this.flipped; + } + + tagIconClick(): void { + const activeModal = this.modalService.open(TagEditModalComponent, { backdrop: 'static', keyboard: false }); + activeModal.componentInstance.device = this.device; + + const tagsList = []; + + this.tags.forEach((nsMap, ns) => { + nsMap.forEach((value, key) => { + tagsList.push({ key: key, value: value, namespace: ns }); + }); + }); + + activeModal.componentInstance.tags = tagsList; + + activeModal.result.then((output: DeviceTag[]) => { + const userTags: { key: string, value: string, namespace: string }[] = <{ key: string, value: string, namespace: string }[]>[]; + + output.filter(tag => tag.namespace === 'pure1-unplugged').forEach(tag => { + userTags.push({ key: tag.key, value: tag.value, namespace: 'pure1-unplugged' }); + }); + + // Create the patch to send + this.tagsService.patch(this.device.id, userTags).subscribe(patchResult => { + // Find any tags that we removed that no longer exist and remove them. + // This is inside the subscribe block to prevent a current API server race condition + // bug: see NSTK-911 + if (!this.tags.has('pure1-unplugged')) { return; } + + const keysToDelete = []; + + this.tags.get('pure1-unplugged').forEach((_, key) => { + if (!userTags.some(t => t.key.localeCompare(key) === 0)) { // Key exists in current tags but not in patched tags: delete it! + keysToDelete.push(key); + } + }); + this.tagsService.deleteTag(this.device.id, keysToDelete.join(',')).pipe(catchError(err => { + console.error(err); + return of(null); + })).subscribe(_ => { }); + }); + }).catch((reason: any) => { + + }); + } + + deleteIconClick() { + const openModal = this.modalService.open(DeviceDeleteModalComponent, { backdrop: 'static', keyboard: false }); + openModal.componentInstance.deviceName = this.device.name; + openModal.result.then(() => { + // DELETE THE DEVICE + this.deviceService.delete(this.device.id).subscribe(x => { }); + }).catch(() => { + // Do nothing, they cancelled + }); + } + + getHighestSeverity(): string { + let highestSeverity = 'none'; // 'none', 'info', 'warning', 'critical' + + this.alerts.forEach(alert => { + switch (alert.Severity) { + case 'info': { + if (highestSeverity === 'none') { + highestSeverity = 'info'; + } + break; + } + case 'warning': { + if (highestSeverity === 'none' || highestSeverity === 'info') { + highestSeverity = 'warning'; + } + break; + } + case 'critical': { + if (highestSeverity !== 'critical') { + highestSeverity = 'critical'; + } + break; + } + } + }); + + return highestSeverity; + } + + trackByNSKey(index, item) { + return item.namespace + ':' + item.key; // Make a consistent value to track by + } + + trackAlertByID(index, item: DeviceAlert) { + return item.ArrayID + '-' + item.AlertID; + } +} diff --git a/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.html b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.html new file mode 100644 index 00000000..7a657230 --- /dev/null +++ b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.html @@ -0,0 +1,27 @@ + +
+ + +
diff --git a/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.scss b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.scss new file mode 100644 index 00000000..ff84c888 --- /dev/null +++ b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.scss @@ -0,0 +1,25 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.modal-header { + .modal-title { + text-transform: none; // Unsetting from standard modal because we don't want the device name to be capitalized + } +} + +.row { + .btn { + margin-left: 15px; + } +} diff --git a/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.spec.ts b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.spec.ts new file mode 100644 index 00000000..2117e752 --- /dev/null +++ b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.spec.ts @@ -0,0 +1,75 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { DeviceDeleteModalComponent } from './device-delete-modal.component'; + +describe('DeviceDeleteModalComponent', () => { + let component: DeviceDeleteModalComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DeviceDeleteModalComponent ], + imports: [ + FormsModule, + ReactiveFormsModule, + NgbModule.forRoot() + ], + providers: [ + NgbActiveModal + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DeviceDeleteModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('shouldn\'t allow deletion when the name doesn\'t match', async () => { + component.deviceName = 'Some Device Name!'; // Set the name to test + const submitButton = fixture.nativeElement.querySelector('input[type="submit"]'); + expect(submitButton.disabled).toBeTruthy(); + + component.nameInput.patchValue('Some Other Name'); // Doesn't match + fixture.detectChanges(); + await fixture.whenStable(); + expect(submitButton.disabled).toBeTruthy(); + + component.nameInput.patchValue('some device name!'); // Equal but different case, doesn't match + fixture.detectChanges(); + await fixture.whenStable(); + expect(submitButton.disabled).toBeTruthy(); + }); + + it('should allow deletion when the name matches', async () => { + component.deviceName = 'Some Device Name!'; // Set the name to test + const submitButton = fixture.nativeElement.querySelector('input[type="submit"]'); + expect(submitButton.disabled).toBeTruthy(); + + component.nameInput.patchValue('Some Device Name!'); + fixture.detectChanges(); + await fixture.whenStable(); + expect(submitButton.disabled).toBeFalsy(); + }); +}); diff --git a/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.ts b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.ts new file mode 100644 index 00000000..7a12421b --- /dev/null +++ b/gui/src/app/modules/device/components/device-delete-modal/device-delete-modal.component.ts @@ -0,0 +1,41 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; + +@Component({ + selector: 'device-delete-modal', + templateUrl: './device-delete-modal.component.html', + styleUrls: ['./device-delete-modal.component.scss'] +}) +export class DeviceDeleteModalComponent implements OnInit { + + @Input() deviceName: string; + nameInput = new FormControl(''); + + constructor(private activeModal: NgbActiveModal) { } + + ngOnInit() { + } + + onCancelClick(): void { + this.activeModal.dismiss(); + } + + onSubmitClick(): void { + this.activeModal.close(); + } +} diff --git a/gui/src/app/modules/device/components/device-list/device-list.component.html b/gui/src/app/modules/device/components/device-list/device-list.component.html new file mode 100644 index 00000000..f67bfabe --- /dev/null +++ b/gui/src/app/modules/device/components/device-list/device-list.component.html @@ -0,0 +1,33 @@ +
+ + + + + + + + + + + + + + + + + + +
+
+
+ +
+ +
diff --git a/gui/src/app/modules/device/components/device-list/device-list.component.scss b/gui/src/app/modules/device/components/device-list/device-list.component.scss new file mode 100644 index 00000000..894e28ad --- /dev/null +++ b/gui/src/app/modules/device/components/device-list/device-list.component.scss @@ -0,0 +1,49 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.search-bars { + padding: 10px 20px; + width: 100%; + display: flex; + flex-direction: row; + flex-wrap: wrap; + + span { + flex-grow: 1; + display: flex; + flex-direction: row; + padding-top: 5px; + } + + & .term-input:last-child { + margin-right: 10px; + } + + .fixed-size { + flex-grow: 0; + + #clear-button { + min-height: 28px; + height: 28px; + } + } +} + +.arrays-view { + padding-top: 15px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; +} diff --git a/gui/src/app/modules/device/components/device-list/device-list.component.ts b/gui/src/app/modules/device/components/device-list/device-list.component.ts new file mode 100644 index 00000000..bfdbf398 --- /dev/null +++ b/gui/src/app/modules/device/components/device-list/device-list.component.ts @@ -0,0 +1,252 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * This component displays the cards for all the devices fetched from + * the device service. + */ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { ListParams } from '../../../../shared/interfaces/list-params'; +import { DeviceAlert } from '../../../../shared/models/device-alert'; +import { DeviceAlertQuery } from '../../../../shared/models/device-alert-query'; +import { StorageDevice } from '../../../../shared/models/storage-device'; +import { DeviceTagsService } from '../../../../shared/services/device-tags.service'; +import { DeviceAlertService } from '../../../device-alert/device-alert.service'; +import { DeviceService } from '../../device.service'; +import { DeviceRegistrationModalComponent } from '../device-registration-modal/device-registration-modal.component'; + +@Component({ + selector: 'device-list', + templateUrl: './device-list.component.html', + styleUrls: ['./device-list.component.scss'] +}) +export class DeviceListComponent implements OnInit, OnDestroy { + devices: StorageDevice[] = []; + tags = new Map>>(); + openAlerts = new Map(); + destroy$: Subject; + deviceCancelSubject: Subject; + + nameQuery: string; + modelQuery: string; + versionQuery: string; + sortQuery: string; + sortDir: 'asc' | 'desc'; + + filter: any[]; + + constructor(private deviceService: DeviceService, private tagsService: DeviceTagsService, private alertService: DeviceAlertService, + private modalService: NgbModal, private router: Router, private route: ActivatedRoute) { } + + ngOnInit() { + this.destroy$ = new Subject(); + this.tagsService.list().pipe(takeUntil(this.destroy$)).subscribe(page => { + this.tags = page.response[0]; + }); + this.alertService.list(new DeviceAlertQuery().withStatus('open')).pipe(takeUntil(this.destroy$)).subscribe(alerts => { + this.openAlerts.clear(); + alerts.results.forEach(alert => { + if (!this.openAlerts.has(alert.ArrayID)) { + this.openAlerts.set(alert.ArrayID, []); + } + + this.openAlerts.get(alert.ArrayID).push(alert); + }); + }); + this.route.queryParams.subscribe(params => { + if (params['filter']) { + this.filter = JSON.parse(params['filter']); + } else { + this.filter = []; + } + + if (params['sort']) { + this.parseSortString(params['sort']); + } else { + this.sortQuery = 'name'; + this.sortDir = 'asc'; + } + + // Set model variables for the text boxes + this.filter.forEach(filter => { + if (filter.entity !== 'device') { return; } + + if (filter.key === 'array') { this.nameQuery = filter.value; } + if (filter.key === 'model') { this.modelQuery = filter.value; } + if (filter.key === 'version') { this.versionQuery = filter.value; } + }); + + this.reconnectDeviceService(); + }); + } + + ngOnDestroy(): void { + console.debug('Unsubscribing from services'); + this.destroy$.next(true); + if (this.deviceCancelSubject) { + this.deviceCancelSubject.next(); + } + } + + registerButtonClick(): void { + this.modalService.open(DeviceRegistrationModalComponent, { backdrop: 'static', keyboard: false }).result.then((output) => { + this.deviceService.create(output).subscribe((createdArray) => { + + }); + }).catch((reason: any) => { + // Do nothing, modal dismissed + }); + } + + trackById(index, item) { + return item.id; + } + + // Renavigates to the devices page, applying the filter and sort + renavigate(clear: boolean): void { + // Clean up the filters before renavigating: while this doesn't ensure clean filters *all* the time (user-entered URLs could be dirty), + // it at least makes sure that when we change them programmatically they end up clean. + this.removeImproperFilters(); + const queryParams = {}; + if (this.filter.length > 0) { + queryParams['filter'] = JSON.stringify(this.filter); + } + if (this.sortQuery && this.sortDir) { + queryParams['sort'] = this.getSortString(); + } + this.router.navigate(['/dash/arrays'], { queryParams: queryParams}); + if (clear) { + this.devices = []; + } + this.reconnectDeviceService(); + } + + reconnectDeviceService() { + if (this.deviceCancelSubject) { + this.deviceCancelSubject.next(); + } + + this.deviceCancelSubject = new Subject(); + + const query: ListParams = {}; + if (this.sortQuery && this.sortDir) { + query.sort = { + key: this.sortQuery, + order: this.sortDir + }; + } + query.filter = {}; + if (this.nameQuery) { + query.filter['names'] = this.nameQuery; + } + if (this.modelQuery) { + query.filter['models'] = this.modelQuery; + } + if (this.versionQuery) { + query.filter['versions'] = this.versionQuery; + } + + this.deviceService.list(query).pipe(takeUntil(this.deviceCancelSubject)).subscribe(page => { + this.devices = page.response; + }); + } + + // Removes filters that are missing a field or have empty fields + removeImproperFilters(): void { + this.filter = this.filter.filter(f => f.hasOwnProperty('entity') && f.entity !== '' && + f.hasOwnProperty('key') && f.key !== '' && + f.hasOwnProperty('value') && f.value !== ''); + } + + getSortString(): string { + if (this.sortDir === 'desc') { + return this.sortQuery + '-'; + } else if (this.sortDir === 'asc') { + return this.sortQuery; + } + } + + parseSortString(toParse: string): void { + if (toParse.endsWith('-')) { + this.sortQuery = toParse.substring(0, toParse.length - 1); + this.sortDir = 'desc'; + } else { + this.sortQuery = toParse; + this.sortDir = 'asc'; + } + } + + // Sets (creates/overwrites) the value for a key in the filter + setFilterKeyValue(key: string, value: string): void { + let keyExists = false; + this.filter.forEach(filter => { + if (filter.entity !== 'device' || filter.key !== key) { return; } + + filter.value = value; + keyExists = true; + }); + if (!keyExists) { + this.filter.push({ entity: 'device', key: key, value: value }); + } + } + + onDeviceNameInputChange(event): void { + this.nameQuery = event; + this.setFilterKeyValue('array', this.nameQuery); + this.renavigate(false); + } + + onDeviceModelInputChange(event): void { + this.modelQuery = event; + this.setFilterKeyValue('model', this.modelQuery); + this.renavigate(false); + } + + onVersionInputChange(event): void { + this.versionQuery = event; + this.setFilterKeyValue('version', this.versionQuery); + this.renavigate(false); + } + + onSortChange(event): void { + this.sortQuery = event; + // Because we're tracking by ID to maintain order, we need to actually *clear* the whole list + // here to force it to reorder. Unfortunate consequence is all cards will flip back over, but + // that's minor + this.renavigate(true); + } + + onSortDirChange(event): void { + this.sortDir = event; + // See onSortChange comment + this.renavigate(true); + } + + clearButtonClick(): void { + this.nameQuery = ''; + this.setFilterKeyValue('array', this.nameQuery); + this.modelQuery = ''; + this.setFilterKeyValue('model', this.modelQuery); + this.versionQuery = ''; + this.setFilterKeyValue('version', this.versionQuery); + this.sortQuery = 'name'; + this.sortDir = 'asc'; + // See onSortChange comment + this.renavigate(true); + } +} diff --git a/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.html b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.html new file mode 100644 index 00000000..b0b709fd --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.html @@ -0,0 +1,10 @@ +
+
+
+ + +
+
+ Add New Array +
+
+
diff --git a/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.scss b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.scss new file mode 100644 index 00000000..0bcb6f8e --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.scss @@ -0,0 +1,44 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.card-div { + width: 285px; + height: 350px; + margin: 0 7px; + text-align: center; + cursor: pointer; + border: 1px solid #c5c5c5; + border-radius: 4px; + background-color: #fff; + color: rgba(0, 0, 0, 0.25); + + + .card-content-wrapper { + /* Disable text highlighting: makes it look weird if it can be highlighted */ + user-select: none; + -ms-user-select: none; + -webkit-user-select: none; + + margin-top: 40%; + text-align: center; + font-weight: 500; + color: #aaa; + font-size: 16px; + + .giant-plus-sign { + font-size: 56px; + line-height: 1; + } + } +} diff --git a/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.spec.ts b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.spec.ts new file mode 100644 index 00000000..ff72d25e --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.spec.ts @@ -0,0 +1,39 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DeviceRegistrationCardComponent } from './device-registration-card.component'; + +describe('DeviceRegistrationCardComponent', () => { + let component: DeviceRegistrationCardComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DeviceRegistrationCardComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DeviceRegistrationCardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.ts b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.ts new file mode 100644 index 00000000..a7012f4b --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-card/device-registration-card.component.ts @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'device-registration-card', + templateUrl: './device-registration-card.component.html', + styleUrls: ['./device-registration-card.component.scss'] +}) +export class DeviceRegistrationCardComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.html b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.html new file mode 100644 index 00000000..38fa4ce3 --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.html @@ -0,0 +1,54 @@ + +
+ + +
diff --git a/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.scss b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.scss new file mode 100644 index 00000000..4f96938d --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.scss @@ -0,0 +1,27 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.col-xs-8 { + display: inline-block; +} + +.modal-body { + padding: 20px; +} + +.row { + .btn { + margin-left: 15px; + } +} diff --git a/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.spec.ts b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.spec.ts new file mode 100644 index 00000000..a16de92c --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.spec.ts @@ -0,0 +1,85 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { NgbActiveModal, NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { CoreModule } from '../../../core/core.module'; +import { DeviceRegistrationModalComponent } from './device-registration-modal.component'; + +describe('DeviceRegistrationModalComponent', () => { + // Shared test components + // All should be set in beforeEach() + let fixture: ComponentFixture = null; + let component: DeviceRegistrationModalComponent = null; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + DeviceRegistrationModalComponent + ], + imports: [ + InlineSVGModule.forRoot(), + CoreModule, + ReactiveFormsModule, + NgbModule.forRoot() + ], + providers: [ + NgbActiveModal + ] + }).compileComponents(); + })); + beforeEach(() => { + fixture = TestBed.createComponent(DeviceRegistrationModalComponent); + component = fixture.debugElement.componentInstance; + component.ngOnInit(); + }); + + it('should create the component', () => { + expect(component).toBeTruthy(); + }); + + it('should have empty defaults', () => { + const form = component.deviceForm; + expect(form).toBeTruthy(); + expect(form.value.array_name).toBe(''); + expect(form.value.mgmt_endpoint).toBe(''); + expect(form.value.api_token).toBe(''); + expect(form.value.device_type).toBe(''); + }); + + it('should update the device type when the api token is changed if we haven\'t changed the device type', async () => { + // Entering a FlashBlade token should change the product type to FlashBlade + component.deviceForm.patchValue({ api_token: 'T-someflashbladetoken' }); + expect(component.deviceForm.value.device_type).toBe('FlashBlade'); + + // Entering a FlashArray token should change the product type to FlashArray + component.deviceForm.patchValue({ api_token: 'someflasharraytoken' }); + expect(component.deviceForm.value.device_type).toBe('FlashArray'); + }); + + it('shouldn\'t update the device type when the api token is changed if we\'ve already changed the device type', async () => { + // Mark the component as dirty (like the user had entered input) + component.deviceForm.controls['device_type'].markAsDirty(); + + // Entering a FlashBlade token shouldn't change it + component.deviceForm.patchValue({ api_token: 'T-someflashbladetoken' }); + expect(component.deviceForm.value.device_type).toBe(''); + + // Nor should entering a FlashArray token + component.deviceForm.patchValue({ api_token: 'someflasharraytoken' }); + expect(component.deviceForm.value.device_type).toBe(''); + }); +}); diff --git a/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.ts b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.ts new file mode 100644 index 00000000..cef5ba1a --- /dev/null +++ b/gui/src/app/modules/device/components/device-registration-modal/device-registration-modal.component.ts @@ -0,0 +1,59 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { StorageDevice } from '../../../../shared/models/storage-device'; + +@Component({ + selector: 'device-registration-modal', + templateUrl: './device-registration-modal.component.html', + styleUrls: ['./device-registration-modal.component.scss'] +}) +export class DeviceRegistrationModalComponent implements OnInit { + deviceForm: FormGroup; + + constructor(private activeModal: NgbActiveModal, private fb: FormBuilder) { + this.deviceForm = this.fb.group({ + array_name: ['', Validators.required ], + mgmt_endpoint: ['', Validators.required ], + api_token: ['', Validators.required ], + device_type: ['', Validators.required ] + }); + this.deviceForm.get('api_token').valueChanges.subscribe((value) => { + // If the user already changed it, don't change it again! + if (this.deviceForm.controls['device_type'].dirty) { return; } + + // Attempt to auto-fill the device type based on the API token + if (value.startsWith('T-')) { + this.deviceForm.patchValue({device_type: 'FlashBlade'}); // Auto-select FB based on the token, since it matches the pattern + } else { + this.deviceForm.patchValue({device_type: 'FlashArray'}); // Doesn't match the FB pattern, so go with FA as default + } + }); + } + + ngOnInit() { } + + onCancelClick(): void { + this.activeModal.dismiss(); + } + + onSubmitClick(): void { + const partial = this.deviceForm.value as Partial; + partial.name = this.deviceForm.get('array_name').value; + this.activeModal.close(partial); + } +} diff --git a/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.html b/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.html new file mode 100644 index 00000000..faaba71d --- /dev/null +++ b/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.html @@ -0,0 +1,47 @@ + +
+ + +
diff --git a/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.scss b/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.scss new file mode 100644 index 00000000..a344a83f --- /dev/null +++ b/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.scss @@ -0,0 +1,111 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +.modal-header { + .modal-title { + text-transform: none; // Unsetting from standard modal because we don't want the device name to be capitalized + } + } + +label { + width: 100%; + + #instruction-text { + font-size: 8pt; + color: #5c5c5c; + } + + textarea { + width: 100%; + height: 200px; + } +} + +.tag-list-wrapper { + position: relative; + max-height: 400px; + overflow: auto; + margin-bottom: 10px; + border-bottom: solid 1px transparent; + + .tl-header { + padding-left: 1px; + + .tl-header-title { + display: inline-block; + width: 255px; + margin-right: 10px; + color: #8d8d8d; + font-size: 110%; + font-weight: 700; + padding-left: 8px; + } + } +} + +.tag-input-wrapper { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: stretch; +} + +.key-input, .value-input { + display: inline-block; + margin: 3px 5px; + width: 40%; + flex: 1; +} + +.tag-delete-icon { + width: 20px; + height: 20px; + padding: 7px 0px; + fill: #8d8d8d; + + :hover { + fill: #cccccc; + } + + .device-delete-icon-svg { + cursor: pointer; + } +} + +.add-tag-button { + min-width: 50px; + padding: 0; + min-height: 22px; + height: 22px; + line-height: 22px; + + #add-text { + margin-left: 2px; + } +} +.ng-invalid:not(form) { + border-left: red; + border-left-width: 5px; + border-left-style: solid; +} + +.modal-content { + width: 600px; +} + +.row { + .btn { + margin-left: 15px; + } +} diff --git a/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.ts b/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.ts new file mode 100644 index 00000000..09ab47b5 --- /dev/null +++ b/gui/src/app/modules/device/components/tag-edit-modal/tag-edit-modal.component.ts @@ -0,0 +1,69 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input, OnInit } from '@angular/core'; +import { FormControl } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { DeviceTag } from '../../../../shared/models/device-tag'; +import { StorageDevice } from '../../../../shared/models/storage-device'; + +@Component({ + selector: 'tag-edit-modal', + templateUrl: './tag-edit-modal.component.html', + styleUrls: ['./tag-edit-modal.component.scss'] +}) +export class TagEditModalComponent implements OnInit { + + testKey = 'asdfasdf'; + testValue = 'fdsafdas'; + + tagsText = new FormControl(''); + tags: DeviceTag[] = []; + + @Input() device: StorageDevice; + + constructor(private activeModal: NgbActiveModal) { } + + ngOnInit() { + } + + containsUserEnteredTags(): boolean { + return this.tags.filter(tag => tag.namespace === 'pure1-unplugged').length > 0; + } + + deleteTagClick(index: number): void { + this.tags.splice(index, 1); + } + + addTagClick(): void { + this.tags.push({key: '', value: '', namespace: 'pure1-unplugged'}); + } + + containsInvalidTag(): boolean { + return this.tags.some(tag => tag.key.trim().length === 0 || tag.value.trim().length === 0); + } + + // Used to maintain consistency in the tags list + trackByIndex(index, item) { + return index; + } + + onCancelClick(): void { + this.activeModal.dismiss(); + } + + onSubmitClick(): void { + this.activeModal.close(this.tags); + } +} diff --git a/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.html b/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.html new file mode 100644 index 00000000..3b43cb84 --- /dev/null +++ b/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.html @@ -0,0 +1,33 @@ +
+
+ + +
+ +
+
+
+
Key is required
+
+
+
Value is required
+
+
diff --git a/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.scss b/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.scss new file mode 100644 index 00000000..997d8779 --- /dev/null +++ b/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.scss @@ -0,0 +1,81 @@ +$invalid-color: #f33b2e; +$valid-color: #c5c5c5; + +.tag-list-item { + margin: 8px 0; + display: flex; + + .edit-key, .edit-value { + padding-left: 8px; + padding-right: 8px; + border: 1px solid $valid-color; + + &.invalid { + border-color: $invalid-color; + } + } + + .edit-key { + margin-right: 10px; + width: 255px; + } + + .edit-value { + flex-grow: 1; + } + + .key-value-wrapper { + border: 1px solid transparent; + border-radius: 4px; + width: 100%; + + &.read-row { + border-color: $valid-color; + &.invalid { + border-color: $invalid-color; + } + + .edit-key, .edit-value { + border-color: transparent; + height: 30px; + } + } + } +} + +.error-messages { + color: $invalid-color; + margin-top: -8px; + margin-bottom: 8px; + font-size: 10px; + + .key-errors { + padding-left: 10px; + width: 255px; + float: left; + } + .value-errors { + padding-left: 10px; + width: 294px; + float: right; + } +} + +.action-icons { + display: inline-block; + flex: none; + cursor: pointer; + margin-left: 10px; + fill: #8d8d8d; + border: none; + background: 0 0; + padding: 0; +} + +.hidden-until-shown { + display: none; + + &.show { + display: inline-block; + } +} diff --git a/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.ts b/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.ts new file mode 100644 index 00000000..7dfb4c92 --- /dev/null +++ b/gui/src/app/modules/device/components/tag-edit-modal/tag-list-item/tag-list-item.component.ts @@ -0,0 +1,65 @@ +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; + +@Component({ + selector: 'tag-list-item', + templateUrl: './tag-list-item.component.html', + styleUrls: ['./tag-list-item.component.scss'] +}) +export class TagListItemComponent implements OnInit { + + hovered = false; + + keyFocused = false; + valueFocused = false; + + keyValue: string; + valueValue: string; + + @Output() + keyChange = new EventEmitter(); + @Output() + valueChange = new EventEmitter(); + @Output() + deleted = new EventEmitter(); + + constructor() { } + + ngOnInit() { + } + + @Input() + get key() { + return this.keyValue; + } + + set key(val) { + this.keyValue = val; + this.keyChange.emit(this.keyValue); + } + + @Input() + get value() { + return this.valueValue; + } + + set value(val) { + this.valueValue = val; + this.valueChange.emit(this.valueValue); + } + + isKeyEmpty(): boolean { + return this.key.trim().length === 0; + } + + isValueEmpty(): boolean { + return this.value.trim().length === 0; + } + + showDeleteIcon(): boolean { + return this.hovered || this.keyFocused || this.valueFocused; + } + + onDeletePressed(): void { + this.deleted.emit(); + } +} diff --git a/gui/src/app/modules/device/device.module.ts b/gui/src/app/modules/device/device.module.ts new file mode 100644 index 00000000..ef775f01 --- /dev/null +++ b/gui/src/app/modules/device/device.module.ts @@ -0,0 +1,67 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouterModule } from '@angular/router'; +import { NgbModalModule, NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'; +import { InlineSVGModule } from 'ng-inline-svg'; +import { CookieService } from 'ngx-cookie-service'; +import { NgSlimScrollModule } from 'ngx-slimscroll'; +import { CoreModule } from '../core/core.module'; +import { DeviceCardComponent } from './components/device-card/device-card.component'; +import { DeviceDeleteModalComponent } from './components/device-delete-modal/device-delete-modal.component'; +import { DeviceListComponent } from './components/device-list/device-list.component'; +import { DeviceRegistrationCardComponent } from './components/device-registration-card/device-registration-card.component'; +import { DeviceRegistrationModalComponent } from './components/device-registration-modal/device-registration-modal.component'; +import { TagEditModalComponent } from './components/tag-edit-modal/tag-edit-modal.component'; +import { TagListItemComponent } from './components/tag-edit-modal/tag-list-item/tag-list-item.component'; + +@NgModule({ + declarations: [ + DeviceCardComponent, + DeviceDeleteModalComponent, + DeviceListComponent, + DeviceRegistrationCardComponent, + DeviceRegistrationModalComponent, + TagEditModalComponent, + TagListItemComponent + ], + imports: [ + BrowserModule, + InlineSVGModule.forRoot(), + NgbModalModule.forRoot(), + FormsModule, + ReactiveFormsModule, + NgbTooltipModule, + CoreModule, + CommonModule, + RouterModule, + NgSlimScrollModule + ], + exports: [ + DeviceCardComponent, + DeviceListComponent + ], + entryComponents: [ + DeviceRegistrationModalComponent, + TagEditModalComponent, + DeviceDeleteModalComponent + ], + bootstrap: [], + providers: [ CookieService ] + }) + export class DeviceModule { } diff --git a/gui/src/app/modules/device/device.service.ts b/gui/src/app/modules/device/device.service.ts new file mode 100644 index 00000000..ec9829f2 --- /dev/null +++ b/gui/src/app/modules/device/device.service.ts @@ -0,0 +1,90 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Provides a service to fetch a list of storage devices. + * Could fetch from a mocked backend or from an HTTP backend. + */ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { merge, Observable, of, Subject, timer } from 'rxjs'; +import { catchError, delayWhen, map, repeatWhen, retryWhen, tap } from 'rxjs/operators'; +import { Collection } from '../../shared/interfaces/collection'; +import { DataPage } from '../../shared/interfaces/data-page'; +import { ListParams, SortParams } from '../../shared/interfaces/list-params'; +import { StorageDevice } from '../../shared/models/storage-device'; + +@Injectable({ + providedIn: 'root' +}) +export class DeviceService implements Collection { + // Should be triggered by calling code whenever a change is made that could require refreshing data. + // Static so all instances of this service get triggered. + static notifyRefresh: Subject = new Subject(); + + API_SERVER_ADDRESS = '/api'; + DEVICES_ENDPOINT = '/arrays'; + + constructor(private http: HttpClient) { } + + create(properties: Partial): Observable { + return this.http.post(this.API_SERVER_ADDRESS + this.DEVICES_ENDPOINT, properties).pipe(map((deviceArray) => { + return deviceArray[0]; // Only get the first item + })).pipe(tap(() => setTimeout(() => DeviceService.notifyRefresh.next(), 1000))); // Trigger a delayed refresh + } + + delete(id: string): Observable { + return this.http.delete(this.API_SERVER_ADDRESS + this.DEVICES_ENDPOINT, { params: { ids: id } }).pipe(map(x => { + return x as string; + })).pipe(tap(() => setTimeout(() => DeviceService.notifyRefresh.next(), 1000))); // Trigger a delayed refresh + } + + list(params?: ListParams): Observable> { + // Default to sorting name ascending (since it just makes the + // most sense) + const queryParams = { + 'sort': 'name' + }; + if (params) { + if (params.filter) { + Object.keys(params.filter).forEach((key: string) => { + queryParams[key] = `*${params.filter[key]}*`; // Make each one a wildcard + }); + } + if (params.sort && (params.sort).key && (params.sort).order) { + const cast = params.sort; + if (cast.order === 'desc') { + queryParams['sort'] = params.sort['key'] + '-'; + } else { + queryParams['sort'] = params.sort['key']; + } + } + } + + return this.http.get(this.API_SERVER_ADDRESS + this.DEVICES_ENDPOINT, + { params: queryParams }).pipe(repeatWhen(delayWhen(() => { + // Repeatedly poke the device service + console.debug('Device list fetch successful.'); + return merge(timer(5000), DeviceService.notifyRefresh.asObservable()); + })), retryWhen(delayWhen(() => { + // Repeatedly poke the device service, slower since we're having a hard time talking to it. + console.log('Device list fetch unsuccessful, retrying.'); + return merge(timer(10000), DeviceService.notifyRefresh.asObservable()); + }))).pipe(map(x => { // Convert to DataPage + return { total: x['response'].length, response: x['response'] }; + })).pipe(catchError(_ => { // In case an error somehow slips through, worst case return an empty page. + return of({ total: 0, response: []}); + })); + } +} diff --git a/gui/src/app/modules/support/components/support/support.component.html b/gui/src/app/modules/support/components/support/support.component.html new file mode 100644 index 00000000..d246ae2f --- /dev/null +++ b/gui/src/app/modules/support/components/support/support.component.html @@ -0,0 +1,7 @@ +
+ +
+ diff --git a/gui/src/app/modules/support/components/support/support.component.scss b/gui/src/app/modules/support/components/support/support.component.scss new file mode 100644 index 00000000..b6da9a5c --- /dev/null +++ b/gui/src/app/modules/support/components/support/support.component.scss @@ -0,0 +1,35 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +p { + font-size: 12pt; + font-weight: 600; + padding-top: 15px; + padding-bottom: 5px; + text-align: center; + vertical-align: center; +} + +iframe { + border-style: none; + height: 100%; + width: 100%; + display: inline-block; +} + +.page-links { + font-weight: 600; + width: 100%; + text-align: center; +} diff --git a/gui/src/app/modules/support/components/support/support.component.ts b/gui/src/app/modules/support/components/support/support.component.ts new file mode 100644 index 00000000..7bd8cb7f --- /dev/null +++ b/gui/src/app/modules/support/components/support/support.component.ts @@ -0,0 +1,29 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'support-view', + templateUrl: './support.component.html', + styleUrls: ['./support.component.scss'] +}) +export class SupportComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/gui/src/app/modules/support/support.module.ts b/gui/src/app/modules/support/support.module.ts new file mode 100644 index 00000000..8d034011 --- /dev/null +++ b/gui/src/app/modules/support/support.module.ts @@ -0,0 +1,22 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { NgModule } from '@angular/core'; +import { SupportComponent } from './components/support/support.component'; + +@NgModule({ + declarations: [SupportComponent], + bootstrap: [] + }) + export class SupportModule { } diff --git a/gui/src/app/shared/interfaces/collection.ts b/gui/src/app/shared/interfaces/collection.ts new file mode 100644 index 00000000..4a203dfd --- /dev/null +++ b/gui/src/app/shared/interfaces/collection.ts @@ -0,0 +1,26 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// tslint:disable:interface-name +import { Observable } from 'rxjs'; +import { DataPage } from './data-page'; +import { ListParams } from './list-params'; + +export interface Collection { + create(properties: Partial): Observable; + delete(id: string): Observable; + // get(name: string, array: string): Observable; + list(params?: ListParams): Observable>; + // update(name: string, array: string, properties: {}): Observable; +} diff --git a/gui/src/app/shared/interfaces/data-page.ts b/gui/src/app/shared/interfaces/data-page.ts new file mode 100644 index 00000000..d4204321 --- /dev/null +++ b/gui/src/app/shared/interfaces/data-page.ts @@ -0,0 +1,21 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// tslint:disable:interface-name +// A wrapper that summarizes the data returned by a call to the .list() api +// of a Collection +export interface DataPage { + total: number; + response: T[]; +} diff --git a/gui/src/app/shared/interfaces/list-params.ts b/gui/src/app/shared/interfaces/list-params.ts new file mode 100644 index 00000000..89ed6c18 --- /dev/null +++ b/gui/src/app/shared/interfaces/list-params.ts @@ -0,0 +1,31 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// tslint:disable:interface-name +// Available parameters for Collection.list() +export interface ListParams { + pageStart?: number; + pageSize?: number; + sort?: SortParams | SortParams[]; + filter?: FilterParams; +} + +export interface SortParams { + key: string; + order: 'asc' | 'desc'; +} + +export interface FilterParams { + [key: string]: string | number; +} diff --git a/gui/src/app/shared/interfaces/sidebar-tab.ts b/gui/src/app/shared/interfaces/sidebar-tab.ts new file mode 100644 index 00000000..88254674 --- /dev/null +++ b/gui/src/app/shared/interfaces/sidebar-tab.ts @@ -0,0 +1,23 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export interface ISidebarTab { + title: string; + active: boolean; + link: string; + icon?: string; + href?: string; + options?: any; + subTabs?: ISidebarTab[]; + } diff --git a/gui/src/app/shared/mocks/device-alert-mock-interceptor.ts b/gui/src/app/shared/mocks/device-alert-mock-interceptor.ts new file mode 100644 index 00000000..657b0095 --- /dev/null +++ b/gui/src/app/shared/mocks/device-alert-mock-interceptor.ts @@ -0,0 +1,156 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { DeviceMockUtil } from './device-mock-util'; + +@Injectable() +export class DeviceAlertMockInterceptor implements HttpInterceptor { + static ALERTS: Map; + static ALERT_TYPES = [ + { + 'component_name': 'c75-4', + 'event': 'failure', + 'severity': 'warning', + 'code': 46 + }, + { + 'component_name': 'ct0', + 'event': 'failure', + 'severity': 'critical', + 'code': 4 + }, + { + 'component_name': 'ct1', + 'event': 'failure', + 'severity': 'critical', + 'code': 4 + }, + { + 'component_name': 'infra', + 'event': 'delayed', + 'severity': 'warning', + 'code': 51 + }, + { + 'component_name': 'array.directory_service', + 'event': 'pureds test failure', + 'severity': 'warning', + 'code': 30 + }, + { + 'component_name': 'ct1.fc5', + 'event': 'Fibre Channel link failure', + 'severity': 'warning', + 'code': 39 + }, + { + 'component_name': 'ct0.fc3', + 'event': 'Fibre Channel link failure', + 'severity': 'warning', + 'code': 39 + } + ]; + + constructor() { + DeviceMockUtil.initialize(); + DeviceAlertMockInterceptor.ALERTS = new Map(); + for (let i = 0; i < DeviceMockUtil.fakeIds.length; i++) { + const alerts = []; + const alertsCount = Math.round(Math.random() * 4); + for (let j = 0; j < alertsCount; j++) { + alerts.push(DeviceAlertMockInterceptor.generateFakeAlert(DeviceMockUtil.fakeIds[i])); + } + DeviceAlertMockInterceptor.ALERTS.set(DeviceMockUtil.fakeIds[i], alerts); + } + } + + static generateFakeAlert(id: string): any { + const alertType = DeviceAlertMockInterceptor.ALERT_TYPES[Math.round(Math.random() * DeviceAlertMockInterceptor.ALERT_TYPES.length)]; + return { + 'severity': alertType.severity, + 'actual': null, + 'variables': null, + 'code': alertType.code, + 'knowledge_base_url': '', + 'created': 0, + 'notified': 0, + 'subject': '', + 'component_name': alertType.component_name, + 'expected': null, + 'description': '', + 'index': 0, + 'opened': 0, + 'component_type': '', + 'component': '', + 'flagged': false, + 'name': '', + 'action': '', + 'details': '', + 'id': 0, + 'state': 'open', + 'category': 'array', + 'event': alertType.event, + 'updated': 0 + }; + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + if (req.url === '/elasticsearch/pure1-unplugged/metrics/_search') { + switch (req.method) { + case 'POST': { + const body = JSON.parse(req.body); + try { + if (body.aggs) { + // Aggregations are what define an alerts fetch: this has them, so it's probably alerts + const buckets = []; + + DeviceMockUtil.fakeIds.forEach(id => { + buckets.push({ + 'top_result': { + 'hits': { + 'hits': [ + { + '_source': { + 'DeviceID': id, + 'Hostname': '', + 'Alerts': DeviceAlertMockInterceptor.ALERTS.get(id) + } + } + ] + } + } + }); + }); + + return of(new HttpResponse({status: 200, body: { + 'aggregations': { + 'unique_id': { + 'buckets': buckets + } + } + }})); + } + } catch (error) { + return next.handle(req); + } + } + } + } + + return next.handle(req); // Return unmodified + } +} diff --git a/gui/src/app/shared/mocks/device-metric-mock-interceptor.ts b/gui/src/app/shared/mocks/device-metric-mock-interceptor.ts new file mode 100644 index 00000000..44662039 --- /dev/null +++ b/gui/src/app/shared/mocks/device-metric-mock-interceptor.ts @@ -0,0 +1,93 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { DeviceMockUtil } from './device-mock-util'; + +@Injectable() +export class DeviceMetricMockInterceptor implements HttpInterceptor { + static METRICS: any[]; + + constructor() { + DeviceMockUtil.initialize(); + DeviceMetricMockInterceptor.METRICS = []; + for (let i = 0; i < DeviceMockUtil.fakeIds.length; i++) { + DeviceMetricMockInterceptor.METRICS.push(DeviceMetricMockInterceptor.generateFakeMetric(DeviceMockUtil.fakeIds[i])); + } + } + + static generateFakeMetric(id: string) { + const volCount = Math.round(Math.random() * 2000); + const activeVolCount = Math.round(Math.random() * volCount); + const totalSpace = Math.random() * 9999999999999; + const usedSpace = Math.random() * totalSpace; + const percentFull = usedSpace / totalSpace; + return { + 'ReadsPerSec': Math.round(Math.random() * 100), + 'HostCount': 71, + 'InputPerSec': Math.round(Math.random() * 100000000), + 'DeviceID': id, + 'OutputPerSec': Math.round(Math.random() * 100000000), + 'CreatedAt': 1538757340, + 'Hostname': '', // Blank at the moment as we don't have a nice way to get this + 'QueueDepth': 2, + 'UsedSpace': usedSpace, + 'PendingEradicateVolumeCount': 0, + 'WritesPerSec': Math.round(Math.random() * 100), + 'VolumeCount': volCount, + 'ActiveVolumeCount': activeVolCount, + 'SnapshotCount': Math.round(Math.random() * 100), + 'AlertMessageCount': 0, + 'HealthScore': 100, + 'TotalReduction': Math.random() * 200, + 'ReadLatency': Math.round(Math.random() * 2000), + 'PercentFull': percentFull, + 'TotalSpace': totalSpace, + 'DataReduction': (Math.random() * 6) + 1, + 'WriteLatency': Math.round(Math.random() * 2000) + }; + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + if (req.url === '/elasticsearch/pure1-unplugged/metrics/_search') { + switch (req.method) { + case 'POST': { + const body = JSON.parse(req.body); + try { + if (!body.aggs) { + // Aggregations are what define an alerts fetch: this has none, so it's probably metrics + const deviceID = body.query.match.DeviceID; + + return of(new HttpResponse({status: 200, body: { + 'hits': { + 'hits': [ + { + '_source': DeviceMetricMockInterceptor.METRICS.find(metric => metric.DeviceID === deviceID) + } + ] + } + }})); + } + } catch (error) { + return next.handle(req); + } + } + } + } + + return next.handle(req); // Return unmodified + } +} diff --git a/gui/src/app/shared/mocks/device-mock-interceptor.ts b/gui/src/app/shared/mocks/device-mock-interceptor.ts new file mode 100644 index 00000000..144e5609 --- /dev/null +++ b/gui/src/app/shared/mocks/device-mock-interceptor.ts @@ -0,0 +1,86 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { StorageDevice } from '../models/storage-device'; +import { DeviceMockUtil } from './device-mock-util'; + +@Injectable() +export class DeviceMockInterceptor implements HttpInterceptor { + static ARRAYS: StorageDevice[] = [ + { + id: '', + name: 'I\'m An Array!', + mgmt_endpoint: '192.168.1.1', + api_token: 'AAAAAHHH', + status: 'Connected', + device_type: 'FlashArray', + model: 'FA-420', + version: '5.1.3', + _as_of: '0', + _last_updated: '0' + }, { + id: '', + name: 'NOT AN ARRAY', + mgmt_endpoint: '1.1.861.291', + api_token: 'AAAAAHHH', + status: 'Connected', + device_type: 'FlashBlade', + model: 'FlashBlade', + version: '1.2.3', + _as_of: '0', + _last_updated: '0' + } + ]; + + constructor() { + DeviceMockUtil.initialize(); + for (let i = 0; i < DeviceMockUtil.fakeIds.length; i++) { + DeviceMockInterceptor.ARRAYS[i].id = DeviceMockUtil.fakeIds[i]; + } + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + if (req.url === '/api/arrays') { + switch (req.method) { + case 'GET': { + if (req.params.has('ids')) { + return of(new HttpResponse({ status: 200, body: DeviceMockInterceptor.ARRAYS + .filter(device => device.id === req.params.get('ids')) + .slice(0, DeviceMockInterceptor.ARRAYS.length) })); + } + + return of(new HttpResponse({ status: 200, body: DeviceMockInterceptor.ARRAYS + .slice(0, DeviceMockInterceptor.ARRAYS.length)})); + } + case 'POST': { + // Don't actually add it, but pretend we did + const newDevice = new StorageDevice(); + newDevice.name = req.body.name; + newDevice.mgmt_endpoint = req.body.mgmt_endpoint; + newDevice.status = 'Connecting'; + return of(new HttpResponse({ status: 200, body: [ newDevice ]})); + } + case 'DELETE': { + // Don't actually delete it, but pretend we did + return of(new HttpResponse({ status: 200, body: 'Deleted.' })); + } + } + } + + return next.handle(req); // Return unmodified + } +} diff --git a/gui/src/app/shared/mocks/device-mock-util.ts b/gui/src/app/shared/mocks/device-mock-util.ts new file mode 100644 index 00000000..585f094f --- /dev/null +++ b/gui/src/app/shared/mocks/device-mock-util.ts @@ -0,0 +1,42 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Provides some shared utilities to aid in the mocking process. + */ +export class DeviceMockUtil { + static fakeIds: string[]; + static initialIdCount = 2; + + static generateFakeId(): string { + const hexChars = '0123456789abcdef'; + const length = 24; + let toReturn = ''; + for (let i = 0; i < length; i++) { + toReturn += hexChars.charAt(Math.random() * hexChars.length); + } + return toReturn; + } + + static initialize() { + if (DeviceMockUtil.fakeIds) { + return; // Already initialized + } + DeviceMockUtil.fakeIds = []; + + for (let i = 0; i < DeviceMockUtil.initialIdCount; i++) { + DeviceMockUtil.fakeIds.push(DeviceMockUtil.generateFakeId()); + } + } +} diff --git a/gui/src/app/shared/mocks/device-tag-mock-interceptor.ts b/gui/src/app/shared/mocks/device-tag-mock-interceptor.ts new file mode 100644 index 00000000..38a76797 --- /dev/null +++ b/gui/src/app/shared/mocks/device-tag-mock-interceptor.ts @@ -0,0 +1,112 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { DeviceTag } from '../models/device-tag'; +import { DeviceMockUtil } from './device-mock-util'; + +@Injectable() +export class DeviceTagMockInterceptor implements HttpInterceptor { + static TAGS: Map; + + constructor() { + DeviceMockUtil.initialize(); + DeviceTagMockInterceptor.TAGS = new Map(); + DeviceMockUtil.fakeIds.forEach(id => { + DeviceTagMockInterceptor.TAGS.set(id, DeviceTagMockInterceptor.generateDefaultTags()); + }); + } + + static generateDefaultTags(): DeviceTag[] { + return [ + { + 'key': 'purestorage.com/backend', + 'namespace': 'psoNamespace', + 'value': 'block' + }, + { + 'key': 'access-mode.purestorage.com/RWX', + 'namespace': 'psoNamespace', + 'value': 'false' + }, + { + 'key': 'protection.purestorage.com/snapshot', + 'namespace': 'psoNamespace', + 'value': 'true' + }, + { + 'key': 'purestorage.com/hostname', + 'namespace': 'psoNamespace', + 'value': '' + }, + { + 'key': 'purestorage.com/family', + 'namespace': 'psoNamespace', + 'value': '' + }, + { + 'key': 'access-mode.purestorage.com/RWO', + 'namespace': 'psoNamespace', + 'value': 'true' + }, + { + 'key': 'access-mode.purestorage.com/ROX', + 'namespace': 'psoNamespace', + 'value': 'false' + }, + { + 'key': 'purestorage.com/id', + 'namespace': 'psoNamespace', + 'value': '01234567-890a-bcde-f012-3456789abc' + } + ]; + } + + intercept(req: HttpRequest, next: HttpHandler): Observable> { + if (req.url === '/api/arrays/tags') { + switch (req.method) { + case 'GET': { + const toReturn = []; + if (req.params.has('ids')) { + toReturn.push({ + 'id': req.params.get('ids'), + 'tags': DeviceTagMockInterceptor.TAGS.get(req.params.get('ids')) + }); + } else { + DeviceMockUtil.fakeIds.forEach(id => { + toReturn.push({ + 'id': id, + 'tags': DeviceTagMockInterceptor.TAGS.get(id) + }); + }); + } + + return of(new HttpResponse({ status: 200, body: toReturn})); + } + case 'PATCH': { + // Don't actually patch it, but pretend we did + return of(new HttpResponse({ status: 200, body: [ 'Patch successful (mocked data)' ]})); + } + case 'DELETE': { + // Don't actually delete it, but pretend we did + return of(new HttpResponse({ status: 200, body: 'Deletion successful (mocked data)' })); + } + } + } + + return next.handle(req); // Return unmodified + } +} diff --git a/gui/src/app/shared/models/device-alert-query.spec.ts b/gui/src/app/shared/models/device-alert-query.spec.ts new file mode 100644 index 00000000..40ce5d46 --- /dev/null +++ b/gui/src/app/shared/models/device-alert-query.spec.ts @@ -0,0 +1,170 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { DeviceAlertQuery } from './device-alert-query'; + +describe('DeviceAlertQuery', () => { + it('should match all on empty query', () => { + const query = new DeviceAlertQuery(); + + expect(query.generateQueryObject()).toEqual({ + 'match_all': {} + }); + }); + + it('should match wildcard name with just name', () => { + const query = new DeviceAlertQuery().withDeviceName('asdf'); + + expect(query.generateQueryObject()).toEqual({ + 'bool': { + 'must': [ + { + 'wildcard': { 'ArrayDisplayName': '*asdf*' } + } + ] + } + }); + }); + + it('should match wildcard summary with just alert summary', () => { + const query = new DeviceAlertQuery().withAlertSummary('some problem'); + + expect(query.generateQueryObject()).toEqual({ + 'bool': { + 'must': [ + { + 'wildcard': { 'Summary': '*some problem*' } + } + ] + } + }); + }); + + it('should match exact status with just status', () => { + const query = new DeviceAlertQuery().withStatus('closed'); + + expect(query.generateQueryObject()).toEqual({ + 'bool': { + 'must': [ + { + 'term': { 'State': 'closed' } + } + ] + } + }); + }); + + it('should match exact severity with just severity', () => { + const query = new DeviceAlertQuery().withSeverity('critical'); + + expect(query.generateQueryObject()).toEqual({ + 'bool': { + 'must': [ + { + 'term': { 'Severity': 'critical' } + } + ] + } + }); + }); + + it('should match all 4 queries if all 4 are set', () => { + const query = new DeviceAlertQuery() + .withDeviceName('asdf') + .withAlertSummary('some problem') + .withStatus('closed') + .withSeverity('critical'); + + expect(query.generateQueryObject()).toEqual({ + 'bool': { + 'must': [ + { + 'wildcard': { 'ArrayDisplayName': '*asdf*'} + }, + { + 'wildcard': { 'Summary': '*some problem*'} + }, + { + 'term': { 'State': 'closed'} + }, + { + 'term': { 'Severity': 'critical'} + } + ] + } + }); + }); + + it('should return an empty string with no sort parameters set', () => { + const query = new DeviceAlertQuery().withSort('', null); + + expect(query.generateSortObject()).toEqual({}); + }); + + it('should return an empty string with the sort direction set to null', () => { + const query = new DeviceAlertQuery().withSort('device_name', null); + + expect(query.generateSortObject()).toEqual({}); + }); + + it('should return the correct field for device_name', () => { + const query = new DeviceAlertQuery().withSort('device_name', 'asc'); + + expect(query.generateSortObject()).toEqual({ + 'ArrayDisplayName': { + 'order': 'asc' + } + }); + }); + + it('should return the correct field for severity', () => { + const query = new DeviceAlertQuery().withSort('severity', 'asc'); + + expect(query.generateSortObject()).toEqual({ + 'SeverityIndex': { + 'order': 'asc' + } + }); + }); + + it('should return the correct field for status', () => { + const query = new DeviceAlertQuery().withSort('state', 'asc'); + + expect(query.generateSortObject()).toEqual({ + 'State': { + 'order': 'asc' + } + }); + }); + + it('should return the correct field for summary', () => { + const query = new DeviceAlertQuery().withSort('summary', 'asc'); + + expect(query.generateSortObject()).toEqual({ + 'Summary.raw': { + 'order': 'asc' + } + }); + }); + + it('should return the correct field for updated', () => { + const query = new DeviceAlertQuery().withSort('created', 'asc'); + + expect(query.generateSortObject()).toEqual({ + 'Created': { + 'order': 'asc' + } + }); + }); +}); diff --git a/gui/src/app/shared/models/device-alert-query.ts b/gui/src/app/shared/models/device-alert-query.ts new file mode 100644 index 00000000..6ebc7867 --- /dev/null +++ b/gui/src/app/shared/models/device-alert-query.ts @@ -0,0 +1,140 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export enum SortFieldEnum { + device_name = 'ArrayDisplayName', + severity = 'SeverityIndex', + created = 'Created', + summary = 'Summary.raw', + state = 'State' +} +export type SortDirection = 'asc' | 'desc'; + +export class DeviceAlertQuery { + deviceName = ''; + alertSummary = ''; + status = ''; + severity = ''; + pageSize = 50; + page = 0; + sort: SortFieldEnum = null; + sortDir: SortDirection = null; + + withDeviceName(name: string): this { + this.deviceName = name; + return this; + } + + withAlertSummary(summary: string): this { + this.alertSummary = summary; + return this; + } + + withStatus(status: string): this { + this.status = status; + return this; + } + + withSeverity(severity: string): this { + this.severity = severity; + return this; + } + + withPageSize(size: number): this { + this.pageSize = size; + return this; + } + + withPage(page: number): this { + this.page = page; + return this; + } + + withSort(sort: string, direction: SortDirection): this { + this.sort = SortFieldEnum[sort]; + this.sortDir = direction; + return this; + } + + isMatchAllQuery(): boolean { + return this.deviceName === '' && this.alertSummary === '' && this.status === '' && this.severity === ''; + } + + generateRequestObject(): object { + return { + 'from': this.page * this.pageSize, + 'size': this.pageSize, + 'sort': this.generateSortObject(), + 'query': this.generateQueryObject() + }; + } + + generateQueryObject(): object { + if (this.isMatchAllQuery()) { + return { + 'match_all': {} + }; + } + + const boolQuery = { + 'bool': { + 'must': [] + } + }; + if (this.deviceName !== '') { + boolQuery.bool.must.push({ + 'wildcard': { + 'ArrayDisplayName': `*${this.deviceName}*` + } + }); + } + if (this.alertSummary !== '') { + boolQuery.bool.must.push({ + 'wildcard': { + 'Summary': `*${this.alertSummary}*` + } + }); + } + + if (this.status !== '') { + boolQuery.bool.must.push({ + 'term': { + 'State': this.status + } + }); + } + + if (this.severity !== '') { + boolQuery.bool.must.push({ + 'term': { + 'Severity': this.severity + } + }); + } + + return boolQuery; + } + + generateSortObject(): object { + if (!this.sort || !this.sortDir) { + return {}; + } + + const toReturn = {}; + toReturn[this.sort] = { + 'order': `${this.sortDir}` + }; + return toReturn; + } +} diff --git a/gui/src/app/shared/models/device-alert-result.ts b/gui/src/app/shared/models/device-alert-result.ts new file mode 100644 index 00000000..0a4ec875 --- /dev/null +++ b/gui/src/app/shared/models/device-alert-result.ts @@ -0,0 +1,27 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { DeviceAlert } from './device-alert'; + +export class DeviceAlertResult { + totalHits: number; + results: DeviceAlert[]; + states: string[]; + + constructor(results: DeviceAlert[], totalHits: number, states: string[]) { + this.results = results; + this.totalHits = totalHits; + this.states = states; + } +} diff --git a/gui/src/app/shared/models/device-alert.ts b/gui/src/app/shared/models/device-alert.ts new file mode 100644 index 00000000..28c26d95 --- /dev/null +++ b/gui/src/app/shared/models/device-alert.ts @@ -0,0 +1,38 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as moment from 'moment'; + +// Classes +type AlertStatusName = 'open' | 'closed'; +type AlertSeverityName = 'info' | 'warning' | 'critical'; + +export class DeviceAlert { + AlertID: number; + ArrayDisplayName: string; + ArrayHostname: string; + ArrayID: string; + ArrayName: string; + Code: number; + Created: moment.Moment; + Severity: AlertSeverityName; + SeverityIndex: number; + State: AlertStatusName; + Summary: string; + + /** Gets the Knowledge Base link for this alert */ + getKBLink(): string { + return `https://pure1.purestorage.com/external/knowledge/?cid=Alert_${this.Code.toString().padStart(4, '0')}`; + } +} diff --git a/gui/src/app/shared/models/device-metric.ts b/gui/src/app/shared/models/device-metric.ts new file mode 100644 index 00000000..9aa9a7b7 --- /dev/null +++ b/gui/src/app/shared/models/device-metric.ts @@ -0,0 +1,59 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export class DeviceMetric { + // Metric metadata: + ArrayID: string; + ArrayName: string; + CreatedAt: number; + DisplayName: string; + + VolumeCount: number; + FileSystemCount: number; + SnapshotCount: number; + VolumePendingEradicationCount: number; + + UsedSpace: number; + TotalSpace: number; + PercentFull: number; + + SharedSpace: number; + SnapshotSpace: number; + SystemSpace: number; + VolumeSpace: number; + + BytesPerOp: number; + BytesPerRead: number; + BytesPerWrite: number; + + WriteBandwidth: number; + ReadBandwidth: number; + + ReadIOPS: number; + WriteIOPS: number; + OtherIOPS: number; + + DataReduction: number; + TotalReduction: number; + + ReadLatency: number; + WriteLatency: number; + OtherLatency: number; + + HostCount: number; + QueueDepth: number; + AlertMessageCount: number; + + Tags: object; +} diff --git a/gui/src/app/shared/models/device-tag.ts b/gui/src/app/shared/models/device-tag.ts new file mode 100644 index 00000000..a5d6805e --- /dev/null +++ b/gui/src/app/shared/models/device-tag.ts @@ -0,0 +1,19 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export class DeviceTag { + namespace: string; + key: string; + value: string; +} diff --git a/gui/src/app/shared/models/storage-device.ts b/gui/src/app/shared/models/storage-device.ts new file mode 100644 index 00000000..d4817c95 --- /dev/null +++ b/gui/src/app/shared/models/storage-device.ts @@ -0,0 +1,26 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +export class StorageDevice { + id: string; // UUID + name: string; // User-chosen display name + mgmt_endpoint: string; // FlashArray and FlashBlade + api_token: string; + status: string; // This could be an enum: to be determined + device_type: string; + model: string; + version: string; + _as_of: string; // Should be Unix standard time format + _last_updated: string; // Should be Unix standard time format +} diff --git a/gui/src/app/shared/services/device-metrics.service.ts b/gui/src/app/shared/services/device-metrics.service.ts new file mode 100644 index 00000000..5957de92 --- /dev/null +++ b/gui/src/app/shared/services/device-metrics.service.ts @@ -0,0 +1,66 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Provides a service to fetch the latest metrics for a device. + */ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, timer } from 'rxjs'; +import { delayWhen, map, repeatWhen, retryWhen } from 'rxjs/operators'; +import { DeviceMetric } from '../models/device-metric'; + +@Injectable({ + providedIn: 'root' +}) +export class DeviceMetricsService { + ELASTIC_ADDRESS = '/elasticsearch'; + METRIC_ENDPOINT = '/pure-arrays-metrics-*/_search'; + + constructor(private http: HttpClient) { } + + getLatestMetric(deviceID: string): Observable { + return this.http.post(this.ELASTIC_ADDRESS + this.METRIC_ENDPOINT, `{ + "sort": { "CreatedAt": "desc" }, + "size": 1, + "query": { + "term": { + "ArrayID": { + "value": "${deviceID}" + } + } + }, + "_source": { + "excludes": ["Tags"] + } + }`, { headers: { 'Content-Type': 'application/json'}}) + .pipe(map(result => result['hits']['hits'][0]['_source'])) // Get the part of the response we need + .pipe(map(result => { + // Convert to the proper class + return Object.assign(new DeviceMetric(), result); + })) + .pipe( + repeatWhen(delayWhen(() => { + // Repeatedly poke the metrics service + console.debug(`Metric fetch for ${deviceID} successful.`); + return timer(5000); + })), + retryWhen(delayWhen(() => { + // Repeatedly poke the metrics service, slower since we're having a hard time talking to it. + console.log(`Metric fetch for ${deviceID} unsuccessful, retrying.`); + return timer(15000); + })) + ); + } +} diff --git a/gui/src/app/shared/services/device-tags.service.ts b/gui/src/app/shared/services/device-tags.service.ts new file mode 100644 index 00000000..674a670b --- /dev/null +++ b/gui/src/app/shared/services/device-tags.service.ts @@ -0,0 +1,95 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Provides a service to fetch a list of tags for all arrays. + * Could fetch from a mocked backend or from an HTTP backend. + */ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { merge, Observable, of, Subject, timer } from 'rxjs'; +import { catchError, delayWhen, map, repeatWhen, retryWhen, tap } from 'rxjs/operators'; +import { Collection } from '../interfaces/collection'; +import { DataPage } from '../interfaces/data-page'; +import { ListParams } from '../interfaces/list-params'; + +@Injectable({ + providedIn: 'root' +}) +export class DeviceTagsService implements Collection>>> { // Device => namespace => key => value + // Should be triggered by calling code whenever a change is made that could require refreshing data. + // Static so all instances of this service get triggered. + static notifyRefresh: Subject = new Subject(); + + API_SERVER_ADDRESS = '/api'; + TAGS_ENDPOINT = '/arrays/tags'; + + constructor(private http: HttpClient) { } + + create(properties: Partial>>>): Observable>>> { + throw new Error('Method not implemented.'); + } + + delete(id: string): Observable { + throw new Error('Method not implemented.'); + } + + list(params?: ListParams): Observable>>>> { + console.debug('Beginning tag list fetch...'); + + return this.http.get(this.API_SERVER_ADDRESS + this.TAGS_ENDPOINT).pipe(repeatWhen(delayWhen(() => { + // Repeatedly poke the tag service + console.debug('Tag list fetch successful.'); + return merge(timer(5000), DeviceTagsService.notifyRefresh.asObservable()); + })), retryWhen(delayWhen(() => { + // Repeatedly poke the tag service, slower since we're having a hard time talking to it. + console.log('Tag list fetch unsuccessful, retrying.'); + return merge(timer(10000), DeviceTagsService.notifyRefresh.asObservable()); + }))).pipe(map((arrayIn) => { + // Convert to a multi-layer map + const toReturn = new Map>>(); + arrayIn['response'].forEach((device) => { + if (!toReturn.has(device.id)) { toReturn.set(device.id, new Map>()); } + if (!device.tags) { + // Usually this means that the array is disconnected + toReturn.set(device.id, new Map>()); + return; + } + + // Has 'id' and 'tags + device.tags.forEach((tag) => { + // Has 'key', 'namespace', and 'value' + if (!toReturn.get(device.id).has(tag.namespace)) { toReturn.get(device.id).set(tag.namespace, new Map()); } + toReturn.get(device.id).get(tag.namespace).set(tag.key, tag.value); + }); + }); + return toReturn; + })).pipe(map(x => { // Convert to DataPage: encapsulate the map in an array to make it work. + return { total: 1, response: [x] }; + })).pipe(catchError(err => { // In case an error somehow slips through, worst case return an empty page. + console.error('Error fetching tags: ' + err); + return of({ total: 0, response: []}); + })); + } + + patch(id: string, tagPatches: {key: string, value: string}[]): Observable { + return this.http.patch(this.API_SERVER_ADDRESS + this.TAGS_ENDPOINT, { tags: tagPatches }, { params: { ids: id }}) + .pipe(tap(() => setTimeout(() => DeviceTagsService.notifyRefresh.next(), 1000))); // Trigger a delayed refresh + } + + deleteTag(id: string, tag: string): Observable { + return this.http.delete(this.API_SERVER_ADDRESS + this.TAGS_ENDPOINT, { params: { ids: id, tags: tag } }) + .pipe(tap(() => setTimeout(() => DeviceTagsService.notifyRefresh.next(), 1000))); // Trigger a delayed refresh + } +} diff --git a/gui/src/assets/.gitkeep b/gui/src/assets/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/gui/src/assets/fonts/ProximaNova.otf b/gui/src/assets/fonts/ProximaNova.otf new file mode 100755 index 00000000..5ff48703 Binary files /dev/null and b/gui/src/assets/fonts/ProximaNova.otf differ diff --git a/gui/src/assets/fonts/ProximaNovaBold.otf b/gui/src/assets/fonts/ProximaNovaBold.otf new file mode 100755 index 00000000..9d9115ac Binary files /dev/null and b/gui/src/assets/fonts/ProximaNovaBold.otf differ diff --git a/gui/src/assets/fonts/ProximaNovaBoldIt.otf b/gui/src/assets/fonts/ProximaNovaBoldIt.otf new file mode 100755 index 00000000..a0f08f4d Binary files /dev/null and b/gui/src/assets/fonts/ProximaNovaBoldIt.otf differ diff --git a/gui/src/assets/fonts/ProximaNovaIt.otf b/gui/src/assets/fonts/ProximaNovaIt.otf new file mode 100755 index 00000000..7ddfd837 Binary files /dev/null and b/gui/src/assets/fonts/ProximaNovaIt.otf differ diff --git a/gui/src/assets/fonts/ProximaNovaLight.otf b/gui/src/assets/fonts/ProximaNovaLight.otf new file mode 100755 index 00000000..e2e11059 Binary files /dev/null and b/gui/src/assets/fonts/ProximaNovaLight.otf differ diff --git a/gui/src/assets/fonts/ProximaNovaLightIt.otf b/gui/src/assets/fonts/ProximaNovaLightIt.otf new file mode 100755 index 00000000..16158031 Binary files /dev/null and b/gui/src/assets/fonts/ProximaNovaLightIt.otf differ diff --git a/gui/src/assets/fonts/ProximaNovaSemibold.otf b/gui/src/assets/fonts/ProximaNovaSemibold.otf new file mode 100755 index 00000000..eec98597 Binary files /dev/null and b/gui/src/assets/fonts/ProximaNovaSemibold.otf differ diff --git a/gui/src/assets/fonts/ProximaNovaSemiboldIt.otf b/gui/src/assets/fonts/ProximaNovaSemiboldIt.otf new file mode 100755 index 00000000..3eb449b4 Binary files /dev/null and b/gui/src/assets/fonts/ProximaNovaSemiboldIt.otf differ diff --git a/gui/src/assets/icons/action/logout.svg b/gui/src/assets/icons/action/logout.svg new file mode 100644 index 00000000..7ea4936a --- /dev/null +++ b/gui/src/assets/icons/action/logout.svg @@ -0,0 +1,9 @@ + + + + diff --git a/gui/src/assets/icons/action/x-action.svg b/gui/src/assets/icons/action/x-action.svg new file mode 100644 index 00000000..84d54b30 --- /dev/null +++ b/gui/src/assets/icons/action/x-action.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/src/assets/icons/secondary/alert_critical.svg b/gui/src/assets/icons/secondary/alert_critical.svg new file mode 100755 index 00000000..270cab2a --- /dev/null +++ b/gui/src/assets/icons/secondary/alert_critical.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/gui/src/assets/icons/secondary/alert_info.svg b/gui/src/assets/icons/secondary/alert_info.svg new file mode 100644 index 00000000..7f8476c6 --- /dev/null +++ b/gui/src/assets/icons/secondary/alert_info.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/gui/src/assets/icons/secondary/alert_warning.svg b/gui/src/assets/icons/secondary/alert_warning.svg new file mode 100755 index 00000000..ec260a16 --- /dev/null +++ b/gui/src/assets/icons/secondary/alert_warning.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/gui/src/assets/images/array_disconnected_icon.svg b/gui/src/assets/images/array_disconnected_icon.svg new file mode 100644 index 00000000..5232689c --- /dev/null +++ b/gui/src/assets/images/array_disconnected_icon.svg @@ -0,0 +1,30 @@ + + + + + + \ No newline at end of file diff --git a/gui/src/assets/images/caret-down.svg b/gui/src/assets/images/caret-down.svg new file mode 100644 index 00000000..7c262e31 --- /dev/null +++ b/gui/src/assets/images/caret-down.svg @@ -0,0 +1 @@ + diff --git a/gui/src/assets/images/chevron-left.svg b/gui/src/assets/images/chevron-left.svg new file mode 100644 index 00000000..23e22115 --- /dev/null +++ b/gui/src/assets/images/chevron-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/src/assets/images/chevron-right.svg b/gui/src/assets/images/chevron-right.svg new file mode 100644 index 00000000..33929dc6 --- /dev/null +++ b/gui/src/assets/images/chevron-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/src/assets/images/favicon.ico b/gui/src/assets/images/favicon.ico new file mode 100644 index 00000000..237ff970 Binary files /dev/null and b/gui/src/assets/images/favicon.ico differ diff --git a/gui/src/assets/images/nginclude/readme.txt b/gui/src/assets/images/nginclude/readme.txt new file mode 100644 index 00000000..1be2ccad --- /dev/null +++ b/gui/src/assets/images/nginclude/readme.txt @@ -0,0 +1,2 @@ +All svgs in here will be put into the Angular template cache. The /nginclude/ subdirectory is excluded during +compilation, so do not include it when referencing the images (use /images/). diff --git a/gui/src/assets/images/nginclude/sidenav-analytics.svg b/gui/src/assets/images/nginclude/sidenav-analytics.svg new file mode 100644 index 00000000..645af08d --- /dev/null +++ b/gui/src/assets/images/nginclude/sidenav-analytics.svg @@ -0,0 +1,11 @@ + + + + + + diff --git a/gui/src/assets/images/nginclude/sidenav-api.svg b/gui/src/assets/images/nginclude/sidenav-api.svg new file mode 100644 index 00000000..8084870f --- /dev/null +++ b/gui/src/assets/images/nginclude/sidenav-api.svg @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/gui/src/assets/images/nginclude/sidenav-array.svg b/gui/src/assets/images/nginclude/sidenav-array.svg new file mode 100644 index 00000000..646ca2eb --- /dev/null +++ b/gui/src/assets/images/nginclude/sidenav-array.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/gui/src/assets/images/nginclude/sidenav-dashboard.svg b/gui/src/assets/images/nginclude/sidenav-dashboard.svg new file mode 100644 index 00000000..4f5f8643 --- /dev/null +++ b/gui/src/assets/images/nginclude/sidenav-dashboard.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/gui/src/assets/images/nginclude/sidenav-message.svg b/gui/src/assets/images/nginclude/sidenav-message.svg new file mode 100644 index 00000000..35ea879b --- /dev/null +++ b/gui/src/assets/images/nginclude/sidenav-message.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/gui/src/assets/images/nginclude/sidenav-support.svg b/gui/src/assets/images/nginclude/sidenav-support.svg new file mode 100644 index 00000000..17b278a9 --- /dev/null +++ b/gui/src/assets/images/nginclude/sidenav-support.svg @@ -0,0 +1,17 @@ + + + + + + + diff --git a/gui/src/assets/images/nginclude/topology_array_icon.svg b/gui/src/assets/images/nginclude/topology_array_icon.svg new file mode 100644 index 00000000..ea5f5913 --- /dev/null +++ b/gui/src/assets/images/nginclude/topology_array_icon.svg @@ -0,0 +1,19 @@ + + + + + diff --git a/gui/src/assets/images/nginclude/topology_datastore_icon.svg b/gui/src/assets/images/nginclude/topology_datastore_icon.svg new file mode 100644 index 00000000..e1a64eed --- /dev/null +++ b/gui/src/assets/images/nginclude/topology_datastore_icon.svg @@ -0,0 +1,21 @@ + + + + + + + diff --git a/gui/src/assets/images/nginclude/topology_host_icon.svg b/gui/src/assets/images/nginclude/topology_host_icon.svg new file mode 100644 index 00000000..898f9c95 --- /dev/null +++ b/gui/src/assets/images/nginclude/topology_host_icon.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/gui/src/assets/images/nginclude/topology_link_icon.svg b/gui/src/assets/images/nginclude/topology_link_icon.svg new file mode 100644 index 00000000..92bd97c7 --- /dev/null +++ b/gui/src/assets/images/nginclude/topology_link_icon.svg @@ -0,0 +1,6 @@ + + + diff --git a/gui/src/assets/images/nginclude/topology_vdisk_icon.svg b/gui/src/assets/images/nginclude/topology_vdisk_icon.svg new file mode 100644 index 00000000..e1261bcc --- /dev/null +++ b/gui/src/assets/images/nginclude/topology_vdisk_icon.svg @@ -0,0 +1,21 @@ + + + + + + diff --git a/gui/src/assets/images/nginclude/topology_vm_icon.svg b/gui/src/assets/images/nginclude/topology_vm_icon.svg new file mode 100644 index 00000000..5ab3a806 --- /dev/null +++ b/gui/src/assets/images/nginclude/topology_vm_icon.svg @@ -0,0 +1,17 @@ + + + diff --git a/gui/src/assets/images/nginclude/topology_volume_icon.svg b/gui/src/assets/images/nginclude/topology_volume_icon.svg new file mode 100644 index 00000000..5e8788ec --- /dev/null +++ b/gui/src/assets/images/nginclude/topology_volume_icon.svg @@ -0,0 +1,19 @@ + + + diff --git a/gui/src/assets/images/pure1_hamburger_menu.svg b/gui/src/assets/images/pure1_hamburger_menu.svg new file mode 100644 index 00000000..c1d3b8ad --- /dev/null +++ b/gui/src/assets/images/pure1_hamburger_menu.svg @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/gui/src/assets/images/pure1_logo_light.svg b/gui/src/assets/images/pure1_logo_light.svg new file mode 100644 index 00000000..721e3ba8 --- /dev/null +++ b/gui/src/assets/images/pure1_logo_light.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/gui/src/assets/images/pure1_unplugged_logo_text_light.svg b/gui/src/assets/images/pure1_unplugged_logo_text_light.svg new file mode 100644 index 00000000..f51684ae --- /dev/null +++ b/gui/src/assets/images/pure1_unplugged_logo_text_light.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gui/src/assets/images/sidebar_collapse_arrow.svg b/gui/src/assets/images/sidebar_collapse_arrow.svg new file mode 100644 index 00000000..ff2f4676 --- /dev/null +++ b/gui/src/assets/images/sidebar_collapse_arrow.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/gui/src/assets/images/tag_icon.svg b/gui/src/assets/images/tag_icon.svg new file mode 100644 index 00000000..3cbda78f --- /dev/null +++ b/gui/src/assets/images/tag_icon.svg @@ -0,0 +1,7 @@ + + + diff --git a/gui/src/assets/styles/_pstg_variables.scss b/gui/src/assets/styles/_pstg_variables.scss new file mode 100644 index 00000000..bc5f8793 --- /dev/null +++ b/gui/src/assets/styles/_pstg_variables.scss @@ -0,0 +1,109 @@ +// Copyright 2019, Pure Storage Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +$pstg-blue: #5ab0ee; +$pstg-orange: #fb5000; +$pstg-green: #71a74f; +$pstg-turquoise: #2ec6c8; +$pstg-yellow: #fac13a; +$pstg-red: #f33b2e; +$pstg-purple: #b5a1dd; +$pstg-gray-darkest: #222222; +$pstg-gray-darker: #454545; +$pstg-gray-dark: #8d8d8d; +$pstg-gray-light: #c5c5c5; +$pstg-gray-lighter: #e6e6e6; +$pstg-gray-lightest: #f7f7f7; +$pstg-orange-hover: #D43C13; +$pstg-yellow-hover: #DB9118; +$pstg-red-hover: #CF1A0D; +$pstg-blue-hover: #248ACA; +$pstg-green-hover: #629640; +$pstg-gray-light-hover: #8d8d8d; +$pstg-gray-lighter-hover: #c5c5c5; +$pstg-gray-dark-hover: #454545; +$pstg-padding: 20px; +$pstg-padding-thin: 15px; +$pstg-border-radius: 4px; +$pstg-border-width: 1px; +$pstg-border-color: #c5c5c5; +$pstg-border-shadow: 0 3px 8px rgba(0, 0, 0, 0.275); +$pstg-font-main-size: 12px; +$pstg-font-main-color: #454545; +$pstg-font-heading1-size: 20px; +$pstg-font-heading1-weight: 600; +$pstg-font-border-box-size: 15px; +$pstg-font-border-box-weight: 600; +$pstg-font-border-box-color: #454545; +$pstg-form-control-height: 30px; +$pstg-form-control-border-radius: 2px; +$pstg-form-control-padding-x: 15px; +$pstg-form-control-padding-y: 6px; +$pstg-form-control-caret-down: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMiAyOCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1heFlNaWQiPjxwb2x5Z29uIHBvaW50cz0iMC4xLDEyLjIgNC41LDE2LjcgOSwxMi4yIi8+PC9zdmc+'); +$pstg-form-control-caret-up: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMiAyOCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1heFlNaWQiPjxwb2x5Z29uIHBvaW50cz0iOSwxNi43IDQuNiwxMi4yIDAuMSwxNi43Ii8+PC9zdmc+'); +$pstg-btn-border-radius: 2px; +$pstg-btn-padding-x: 15px; +$pstg-btn-padding-y: .4rem; +$pstg-btn-height: 30px; +$pstg-btn-primary-color: white; +$pstg-btn-primary-background-color: #5ab0ee; +$pstg-btn-primary-border-color: #47a2e4; +$pstg-btn-secondary-color: #454545; +$pstg-btn-secondary-background-color: white; +$pstg-btn-secondary-border-color: #c5c5c5; +$pstg-btn-info-color: white; +$pstg-btn-info-background-color: #8d8d8d; +$pstg-btn-info-border-color: #808080; +$pstg-btn-success-color: white; +$pstg-btn-success-background-color: #fb5000; +$pstg-btn-success-border-color: #e34800; +$pstg-btn-danger-color: white; +$pstg-btn-danger-background-color: #f33b2e; +$pstg-btn-danger-border-color: #e32a1d; +$pstg-btn-icon-height: 16px; +$pstg-topbar-height: 55px; +$pstg-topbar-background-color: #dedede; +$pstg-topbar-right-margin-y: 5px; +$pstg-topbar-right-margin-x: 10px; +$pstg-topbar-icon-height: 20px; +$pstg-summary-icon-height: 20px; +$pstg-navbar-font-size: 16px; +$pstg-navbar-height: 43px; +$pstg-navbar-pill-height: 4px; +$pstg-sidebar-expanded-width: 204px; +$pstg-sidebar-collapsed-width: 70px; +$pstg-sidebar-mobile-mode-width: 768px; +$pstg-sidebar-slide-transition-duration: 0.5s; +$pstg-sidebar-slide-transition-timing-function: ease; +$pstg-left-nav-width: 350px; +$pstg-border-box-header-min-height: 36px; +$pstg-border-box-padding-y: 5px; +$pstg-capacity-file-systems-color: #52C8FD; +$pstg-capacity-object-stores-color: #4384B1; +$pstg-capacity-volumes-color: #2EC6C8; +$pstg-capacity-snapshots-color: #B5A1DD; +$pstg-capacity-shared-space-color: #55C707; +$pstg-capacity-system-color: #B8BEBE; +$pstg-capacity-empty-color: #F4F2F3; +$pstg-capacity-total-color: #F37430; +$pstg-table-head-font-size: 15px; +$pstg-table-head-font-weight: 600; +$pstg-table-internal-separator-color: #ddd; +$pstg-table-row-hover-background-color: #f0f0f0; +$pstg-table-row-active-background-color: #e6e6e6; +$pstg-table-cell-padding-x: 20px; +$pstg-table-cell-padding-y: 5px; +$pstg-table-max-array-name-cell-width: 100px; +$pstg-modal-header-font-size: 15px; +$pstg-modal-header-font-weight: 600; diff --git a/gui/src/assets/styles/bootstrap.css b/gui/src/assets/styles/bootstrap.css new file mode 100644 index 00000000..357b4779 --- /dev/null +++ b/gui/src/assets/styles/bootstrap.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.0.0-alpha.5 (https://getbootstrap.com) + * Copyright 2011-2016 The Bootstrap Authors + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */progress,sub,sup{vertical-align:baseline}address,dl,ol,p,ul{margin-bottom:1rem}caption,th{text-align:left}html,legend{box-sizing:border-box}.custom-select,input[type=search]{-webkit-appearance:none}button,hr,input{overflow:visible}pre,textarea{overflow:auto}.btn-group>.btn-group,.btn-toolbar .btn-group,.btn-toolbar .input-group,.dropdown-menu,.table-reflow thead,.table-reflow tr{float:left}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNovaLight.otf) format("opentype");font-weight:300;font-style:normal}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNovaLightIt.otf) format("opentype");font-weight:300;font-style:italic}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNova.otf) format("opentype");font-weight:400;font-style:normal}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNovaIt.otf) format("opentype");font-weight:400;font-style:italic}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNovaSemibold.otf) format("opentype");font-weight:600;font-style:normal}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNovaSemiboldIt.otf) format("opentype");font-weight:600;font-style:italic}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNovaBold.otf) format("opentype");font-weight:700;font-style:normal}@font-face{font-family:"Proxima Nova";src:url(../fonts/ProximaNovaBoldIt.otf) format("opentype");font-weight:700;font-style:italic}/*! normalize.css v4.2.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}h1{margin:.67em 0}dd,h1,h2,h3,h4,h5,h6,label{margin-bottom:.5rem}mark{color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none;vertical-align:middle}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}textarea{resize:vertical}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}dt,kbd kbd{font-weight:700}address,button,input,legend,select,textarea{line-height:inherit}@media print{blockquote,img,pre,tr{page-break-inside:avoid}*,::after,::before,::first-letter,blockquote::first-line,div::first-line,li::first-line,p::first-line{text-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #999}thead{display:table-header-group}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.tag{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}label,output{display:inline-block}html{font-size:12px;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}*,::after,::before{box-sizing:inherit}@-ms-viewport{width:device-width}body{margin:0;font-family:"Proxima Nova",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:1rem;line-height:1.5;color:#454545;background-color:#e6e6e6}[tabindex="-1"]:focus{outline:0!important}dl,h1,h2,h3,h4,h5,h6,ol,p,ul{margin-top:0}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #c5c5c5}address{font-style:normal}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dd{margin-left:0}blockquote,figure{margin:0 0 1rem}a{color:#5ab0ee;text-decoration:none}a:focus,a:hover{color:#178ee4;text-decoration:underline}a:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}a:not([href]):not([tabindex]),a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}[role=button]{cursor:pointer}.form-control:disabled,input[type=checkbox]:disabled,input[type=radio]:disabled{cursor:not-allowed}[role=button],a,area,button,input,label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse;background-color:#fff}caption{padding-top:5px 20px;padding-bottom:5px 20px;color:#c5c5c5;caption-side:bottom}button:focus{outline:dotted 1px;outline:-webkit-focus-ring-color auto 5px}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}fieldset{min-width:0;padding:0;margin:0;border:0}legend{color:inherit;max-width:100%;white-space:normal;display:block;width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem}.btn,.dropdown-header,.dropdown-item,.input-group-btn,.table-reflow tbody,.tag{white-space:nowrap}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.blockquote,hr{margin-bottom:1rem}.display-1,.display-2,.display-3,.display-4,.lead{font-weight:300}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem}.display-1{font-size:6rem}.display-2{font-size:5.5rem}.display-3{font-size:4.5rem}.display-4{font-size:3.5rem}hr{box-sizing:content-box;height:0;margin-top:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img,.img-fluid,.img-thumbnail{height:auto;max-width:100%}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#cee7fa}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:5px}.container,.container-fluid{margin-left:auto;margin-right:auto}.initialism{font-size:90%;text-transform:uppercase}.blockquote{padding:.5rem 1rem;font-size:1.25rem;border-left:.25rem solid #e6e6e6}.blockquote-footer{display:block;font-size:80%;color:#c5c5c5}.blockquote-footer::before{content:"\2014 \00A0"}.blockquote-reverse{padding-right:1rem;padding-left:0;text-align:right;border-right:.25rem solid #e6e6e6;border-left:0}.blockquote-reverse .blockquote-footer::before{content:""}.blockquote-reverse .blockquote-footer::after{content:"\00A0 \2014"}.btn-group-vertical>.btn-group::after,.btn-toolbar::after,.dropdown-toggle::after{content:""}.img-thumbnail{padding:.25rem;background-color:#e6e6e6;border:1px solid #ddd;border-radius:4px;transition:all .2s ease-in-out}code,kbd{padding:.2rem .4rem;font-size:90%;border-radius:4px}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.table,pre{margin-bottom:1rem}.figure-caption{font-size:90%;color:#c5c5c5}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}code{color:#bd4147;background-color:#f7f7f9}kbd{color:#fff;background-color:#333}kbd kbd{padding:0;font-size:100%}.btn,.btn-link,.dropdown-item{font-weight:400}pre{display:block;margin-top:0;font-size:90%;color:#454545}pre code{padding:0;font-size:inherit;color:inherit;background-color:transparent;border-radius:0}.container,.container-fluid{padding-right:10px;padding-left:10px}.pre-scrollable{max-height:340px;overflow-y:scroll}.row{display:flex;flex-wrap:wrap;margin-right:-10px;margin-left:-10px}@media (min-width:576px){.container{width:540px;max-width:100%}.row{margin-right:-10px;margin-left:-10px}.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{padding-right:10px;padding-left:10px}}@media (min-width:768px){.container{width:768px;max-width:100%}.row{margin-right:-10px;margin-left:-10px}.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{padding-right:10px;padding-left:10px}}@media (min-width:992px){.container{width:960px;max-width:100%}.row{margin-right:-10px;margin-left:-10px}.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{padding-right:10px;padding-left:10px}}@media (min-width:1200px){.container{width:1140px;max-width:100%}.row{margin-right:-10px;margin-left:-10px}.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{padding-right:10px;padding-left:10px}}.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xs,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;width:100%;padding-right:10px;padding-left:10px}.col-xs{flex-basis:0;flex-grow:1;max-width:100%}.col-xs-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xs-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xs-3{flex:0 0 25%;max-width:25%}.col-xs-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xs-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xs-6{flex:0 0 50%;max-width:50%}.col-xs-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xs-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xs-9{flex:0 0 75%;max-width:75%}.col-xs-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xs-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xs-12{flex:0 0 100%;max-width:100%}.pull-xs-0{right:auto}.pull-xs-1{right:8.33333%}.pull-xs-2{right:16.66667%}.pull-xs-3{right:25%}.pull-xs-4{right:33.33333%}.pull-xs-5{right:41.66667%}.pull-xs-6{right:50%}.pull-xs-7{right:58.33333%}.pull-xs-8{right:66.66667%}.pull-xs-9{right:75%}.pull-xs-10{right:83.33333%}.pull-xs-11{right:91.66667%}.pull-xs-12{right:100%}.push-xs-0{left:auto}.push-xs-1{left:8.33333%}.push-xs-2{left:16.66667%}.push-xs-3{left:25%}.push-xs-4{left:33.33333%}.push-xs-5{left:41.66667%}.push-xs-6{left:50%}.push-xs-7{left:58.33333%}.push-xs-8{left:66.66667%}.push-xs-9{left:75%}.push-xs-10{left:83.33333%}.push-xs-11{left:91.66667%}.push-xs-12{left:100%}.offset-xs-1{margin-left:8.33333%}.offset-xs-2{margin-left:16.66667%}.offset-xs-3{margin-left:25%}.offset-xs-4{margin-left:33.33333%}.offset-xs-5{margin-left:41.66667%}.offset-xs-6{margin-left:50%}.offset-xs-7{margin-left:58.33333%}.offset-xs-8{margin-left:66.66667%}.offset-xs-9{margin-left:75%}.offset-xs-10{margin-left:83.33333%}.offset-xs-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.pull-sm-0{right:auto}.pull-sm-1{right:8.33333%}.pull-sm-2{right:16.66667%}.pull-sm-3{right:25%}.pull-sm-4{right:33.33333%}.pull-sm-5{right:41.66667%}.pull-sm-6{right:50%}.pull-sm-7{right:58.33333%}.pull-sm-8{right:66.66667%}.pull-sm-9{right:75%}.pull-sm-10{right:83.33333%}.pull-sm-11{right:91.66667%}.pull-sm-12{right:100%}.push-sm-0{left:auto}.push-sm-1{left:8.33333%}.push-sm-2{left:16.66667%}.push-sm-3{left:25%}.push-sm-4{left:33.33333%}.push-sm-5{left:41.66667%}.push-sm-6{left:50%}.push-sm-7{left:58.33333%}.push-sm-8{left:66.66667%}.push-sm-9{left:75%}.push-sm-10{left:83.33333%}.push-sm-11{left:91.66667%}.push-sm-12{left:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.pull-md-0{right:auto}.pull-md-1{right:8.33333%}.pull-md-2{right:16.66667%}.pull-md-3{right:25%}.pull-md-4{right:33.33333%}.pull-md-5{right:41.66667%}.pull-md-6{right:50%}.pull-md-7{right:58.33333%}.pull-md-8{right:66.66667%}.pull-md-9{right:75%}.pull-md-10{right:83.33333%}.pull-md-11{right:91.66667%}.pull-md-12{right:100%}.push-md-0{left:auto}.push-md-1{left:8.33333%}.push-md-2{left:16.66667%}.push-md-3{left:25%}.push-md-4{left:33.33333%}.push-md-5{left:41.66667%}.push-md-6{left:50%}.push-md-7{left:58.33333%}.push-md-8{left:66.66667%}.push-md-9{left:75%}.push-md-10{left:83.33333%}.push-md-11{left:91.66667%}.push-md-12{left:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.pull-lg-0{right:auto}.pull-lg-1{right:8.33333%}.pull-lg-2{right:16.66667%}.pull-lg-3{right:25%}.pull-lg-4{right:33.33333%}.pull-lg-5{right:41.66667%}.pull-lg-6{right:50%}.pull-lg-7{right:58.33333%}.pull-lg-8{right:66.66667%}.pull-lg-9{right:75%}.pull-lg-10{right:83.33333%}.pull-lg-11{right:91.66667%}.pull-lg-12{right:100%}.push-lg-0{left:auto}.push-lg-1{left:8.33333%}.push-lg-2{left:16.66667%}.push-lg-3{left:25%}.push-lg-4{left:33.33333%}.push-lg-5{left:41.66667%}.push-lg-6{left:50%}.push-lg-7{left:58.33333%}.push-lg-8{left:66.66667%}.push-lg-9{left:75%}.push-lg-10{left:83.33333%}.push-lg-11{left:91.66667%}.push-lg-12{left:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.pull-xl-0{right:auto}.pull-xl-1{right:8.33333%}.pull-xl-2{right:16.66667%}.pull-xl-3{right:25%}.pull-xl-4{right:33.33333%}.pull-xl-5{right:41.66667%}.pull-xl-6{right:50%}.pull-xl-7{right:58.33333%}.pull-xl-8{right:66.66667%}.pull-xl-9{right:75%}.pull-xl-10{right:83.33333%}.pull-xl-11{right:91.66667%}.pull-xl-12{right:100%}.push-xl-0{left:auto}.push-xl-1{left:8.33333%}.push-xl-2{left:16.66667%}.push-xl-3{left:25%}.push-xl-4{left:33.33333%}.push-xl-5{left:41.66667%}.push-xl-6{left:50%}.push-xl-7{left:58.33333%}.push-xl-8{left:66.66667%}.push-xl-9{left:75%}.push-xl-10{left:83.33333%}.push-xl-11{left:91.66667%}.push-xl-12{left:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;max-width:100%}.table td,.table th{padding:5px 20px;vertical-align:top;border-top:1px solid #c5c5c5}.table thead th{vertical-align:bottom;border-bottom:2px solid #c5c5c5}.table tbody+tbody{border-top:2px solid #c5c5c5}.table .table{background-color:#e6e6e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #c5c5c5}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{background-color:#f0f0f0}.table-active,.table-active>td,.table-active>th{background-color:#e6e6e6}.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#d9d9d9}.table-success,.table-success>td,.table-success>th{background-color:#dff0d8}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#d0e9c6}.table-info,.table-info>td,.table-info>th{background-color:#d9edf7}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#c4e3f3}.table-warning,.table-warning>td,.table-warning>th{background-color:#fcf8e3}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#faf2cc}.table-danger,.table-danger>td,.table-danger>th{background-color:#f2dede}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#ebcccc}.thead-inverse th{color:#fff;background-color:#454545}.thead-default th{color:#8d8d8d;background-color:#e6e6e6}.table-inverse{color:#e6e6e6;background-color:#454545}.table-inverse td,.table-inverse th,.table-inverse thead th{border-color:#8d8d8d}.table-inverse.table-bordered{border:0}.table-responsive{display:block;width:100%;min-height:0;overflow-x:auto}.collapsing,.embed-responsive,.modal,.modal-open,.navbar-divider{overflow:hidden}.table-reflow tbody{display:block}.table-reflow td,.table-reflow th{border-top:1px solid #c5c5c5;border-left:1px solid #c5c5c5}.table-reflow td:last-child,.table-reflow th:last-child{border-right:1px solid #c5c5c5}.table-reflow tbody:last-child tr:last-child td,.table-reflow tbody:last-child tr:last-child th,.table-reflow tfoot:last-child tr:last-child td,.table-reflow tfoot:last-child tr:last-child th,.table-reflow thead:last-child tr:last-child td,.table-reflow thead:last-child tr:last-child th{border-bottom:1px solid #c5c5c5}.table-reflow tr td,.table-reflow tr th{display:block!important;border:1px solid #c5c5c5}.form-check,.form-control,.form-control-file,.form-control-range,.form-text{display:block}.form-control{width:100%;padding:6px 15px;font-size:1rem;line-height:1.25;color:#454545;background-color:#fff;background-image:none;background-clip:padding-box;border:1px solid #c5c5c5;border-radius:2px;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#454545;background-color:#fff;border-color:#66afe9;outline:0}.form-control::placeholder{color:#8d8d8d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e6e6e6;opacity:1}select.form-control:not([size]):not([multiple]){height:calc(30px - 2px)}select.form-control:focus::-ms-value{color:#454545;background-color:#fff}.col-form-label{padding-top:6px;padding-bottom:6px;margin-bottom:0}.col-form-label-lg{padding-top:.75rem;padding-bottom:.75rem;font-size:1.25rem}.col-form-label-sm{padding-top:.25rem;padding-bottom:.25rem;font-size:.875rem}.col-form-legend{padding-top:6px;padding-bottom:6px;margin-bottom:0;font-size:1rem}.form-control-static{padding-top:6px;padding-bottom:6px;line-height:1.25;border:solid transparent;border-width:1px 0}.form-control-static.form-control-lg,.form-control-static.form-control-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-right:0;padding-left:0}.form-control-sm,.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:4px}.input-group-sm>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-sm>select.form-control:not([size]):not([multiple]),.input-group-sm>select.input-group-addon:not([size]):not([multiple]),select.form-control-sm:not([size]):not([multiple]){height:1.8125rem}.form-control-lg,.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:4px}.input-group-lg>.input-group-btn>select.btn:not([size]):not([multiple]),.input-group-lg>select.form-control:not([size]):not([multiple]),.input-group-lg>select.input-group-addon:not([size]):not([multiple]),select.form-control-lg:not([size]):not([multiple]){height:3.16667rem}.form-group{margin-bottom:5px}.form-text{margin-top:.25rem}.form-check{position:relative;margin-bottom:.75rem}.form-check+.form-check{margin-top:-.25rem}.form-check-input,.form-control-feedback{margin-top:.25rem}.form-check.disabled .form-check-label{color:#c5c5c5;cursor:not-allowed}.form-check-inline,.form-check-label{padding-left:1.25rem;margin-bottom:0;cursor:pointer}.form-check-input{position:absolute;margin-left:-1.25rem}.form-check-input:only-child{position:static}.collapsing,.dropdown,.dropup{position:relative}.form-check-inline{position:relative;display:inline-block;vertical-align:middle}.form-check-inline+.form-check-inline{margin-left:.75rem}.form-check-inline.disabled{color:#c5c5c5;cursor:not-allowed}.form-control-danger,.form-control-success,.form-control-warning{padding-right:45px;background-repeat:no-repeat;background-position:center right 7.5px;background-size:15px 15px}.has-success .custom-control,.has-success .form-check-inline,.has-success .form-check-label,.has-success .form-control-feedback,.has-success .form-control-label{color:#71a74f}.has-success .form-control{border-color:#71a74f}.has-success .form-control:focus{box-shadow:none,0 0 6px #a7cb91}.has-success .input-group-addon{color:#71a74f;border-color:#71a74f;background-color:#dfecd6}.has-success .form-control-success{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#71a74f' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E")}.has-warning .custom-control,.has-warning .form-check-inline,.has-warning .form-check-label,.has-warning .form-control-feedback,.has-warning .form-control-label{color:#fac13a}.has-warning .form-control{border-color:#fac13a}.has-warning .form-control:focus{box-shadow:none,0 0 6px #fde09d}.has-warning .input-group-addon{color:#fac13a;border-color:#fac13a;background-color:#fff}.has-warning .form-control-warning{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#fac13a' d='M4.4 5.324h-.8v-2.46h.8zm0 1.42h-.8V5.89h.8zM3.76.63L.04 7.075c-.115.2.016.425.26.426h7.397c.242 0 .372-.226.258-.426C6.726 4.924 5.47 2.79 4.253.63c-.113-.174-.39-.174-.494 0z'/%3E%3C/svg%3E")}.has-danger .custom-control,.has-danger .form-check-inline,.has-danger .form-check-label,.has-danger .form-control-feedback,.has-danger .form-control-label{color:#f33b2e}.has-danger .form-control{border-color:#f33b2e}.has-danger .form-control:focus{box-shadow:none,0 0 6px #f9958e}.has-danger .input-group-addon{color:#f33b2e;border-color:#f33b2e;background-color:#fef0ef}.has-danger .form-control-danger{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='#f33b2e' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E")}@media (min-width:576px){.form-inline .form-control-static,.form-inline .form-group{display:inline-block}.form-inline .form-check,.form-inline .form-control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;width:auto;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .form-check{display:inline-block;margin-top:0}.form-inline .form-check-label{padding-left:0}.form-inline .form-check-input{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.btn-block,input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.btn{display:inline-block;line-height:1.25;text-align:center;vertical-align:middle;cursor:pointer;user-select:none;border:1px solid transparent;padding:.4rem 15px;font-size:1rem;border-radius:2px;transition:all .2s ease-in-out}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0}.btn.disabled,.btn:disabled{cursor:not-allowed;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#5ab0ee;border-color:#47a2e4}.btn-primary.focus,.btn-primary:focus,.btn-primary:hover{color:#fff;background-color:#2c9ae9;border-color:#1e85cf}.btn-primary.active,.btn-primary:active,.open>.btn-primary.dropdown-toggle{color:#fff;background-color:#2c9ae9;border-color:#1e85cf;background-image:none}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.btn-primary.dropdown-toggle.focus,.open>.btn-primary.dropdown-toggle:focus,.open>.btn-primary.dropdown-toggle:hover{color:#fff;background-color:#1789db;border-color:#166096}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary:disabled.focus,.btn-primary:disabled:focus,.btn-primary:disabled:hover{background-color:#5ab0ee;border-color:#47a2e4}.btn-secondary{color:#454545;background-color:#fff;border-color:#c5c5c5}.btn-secondary.focus,.btn-secondary:focus,.btn-secondary:hover{color:#454545;background-color:#e6e6e6;border-color:#a6a6a6}.btn-secondary.active,.btn-secondary:active,.open>.btn-secondary.dropdown-toggle{color:#454545;background-color:#e6e6e6;border-color:#a6a6a6;background-image:none}.btn-secondary.active.focus,.btn-secondary.active:focus,.btn-secondary.active:hover,.btn-secondary:active.focus,.btn-secondary:active:focus,.btn-secondary:active:hover,.open>.btn-secondary.dropdown-toggle.focus,.open>.btn-secondary.dropdown-toggle:focus,.open>.btn-secondary.dropdown-toggle:hover{color:#454545;background-color:#d4d4d4;border-color:#858585}.btn-secondary.disabled.focus,.btn-secondary.disabled:focus,.btn-secondary.disabled:hover,.btn-secondary:disabled.focus,.btn-secondary:disabled:focus,.btn-secondary:disabled:hover{background-color:#fff;border-color:#c5c5c5}.btn-info{color:#fff;background-color:#8d8d8d;border-color:grey}.btn-info.focus,.btn-info:focus,.btn-info:hover{color:#fff;background-color:#747474;border-color:#616161}.btn-info.active,.btn-info:active,.open>.btn-info.dropdown-toggle{color:#fff;background-color:#747474;border-color:#616161;background-image:none}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.btn-info.dropdown-toggle.focus,.open>.btn-info.dropdown-toggle:focus,.open>.btn-info.dropdown-toggle:hover{color:#fff;background-color:#626262;border-color:#404040}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info:disabled.focus,.btn-info:disabled:focus,.btn-info:disabled:hover{background-color:#8d8d8d;border-color:grey}.btn-success{color:#fff;background-color:#fb5000;border-color:#e34800}.btn-success.focus,.btn-success:focus,.btn-success:hover{color:#fff;background-color:#c84000;border-color:#a63500}.btn-success.active,.btn-success:active,.open>.btn-success.dropdown-toggle{color:#fff;background-color:#c84000;border-color:#a63500;background-image:none}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.btn-success.dropdown-toggle.focus,.open>.btn-success.dropdown-toggle:focus,.open>.btn-success.dropdown-toggle:hover{color:#fff;background-color:#a43400;border-color:#642000}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success:disabled.focus,.btn-success:disabled:focus,.btn-success:disabled:hover{background-color:#fb5000;border-color:#e34800}.btn-warning{color:#fff;background-color:#fac13a;border-color:#fac13a}.btn-warning.focus,.btn-warning:focus,.btn-warning:hover{color:#fff;background-color:#f9b108;border-color:#f1ab06}.btn-warning.active,.btn-warning:active,.open>.btn-warning.dropdown-toggle{color:#fff;background-color:#f9b108;border-color:#f1ab06;background-image:none}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.btn-warning.dropdown-toggle.focus,.open>.btn-warning.dropdown-toggle:focus,.open>.btn-warning.dropdown-toggle:hover{color:#fff;background-color:#d89905;border-color:#b07d04}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning:disabled.focus,.btn-warning:disabled:focus,.btn-warning:disabled:hover{background-color:#fac13a;border-color:#fac13a}.btn-danger{color:#fff;background-color:#f33b2e;border-color:#e32a1d}.btn-danger.focus,.btn-danger:focus,.btn-danger:hover{color:#fff;background-color:#e11b0d;border-color:#ad1f15}.btn-danger.active,.btn-danger:active,.open>.btn-danger.dropdown-toggle{color:#fff;background-color:#e11b0d;border-color:#ad1f15;background-image:none}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.btn-danger.dropdown-toggle.focus,.open>.btn-danger.dropdown-toggle:focus,.open>.btn-danger.dropdown-toggle:hover{color:#fff;background-color:#bf170b;border-color:#72150e}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger:disabled.focus,.btn-danger:disabled:focus,.btn-danger:disabled:hover{background-color:#f33b2e;border-color:#e32a1d}.btn-outline-primary{color:#5ab0ee;background-image:none;background-color:transparent;border-color:#5ab0ee}.btn-outline-primary.active,.btn-outline-primary.focus,.btn-outline-primary:active,.btn-outline-primary:focus,.btn-outline-primary:hover,.open>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#5ab0ee;border-color:#5ab0ee}.btn-outline-primary.active.focus,.btn-outline-primary.active:focus,.btn-outline-primary.active:hover,.btn-outline-primary:active.focus,.btn-outline-primary:active:focus,.btn-outline-primary:active:hover,.open>.btn-outline-primary.dropdown-toggle.focus,.open>.btn-outline-primary.dropdown-toggle:focus,.open>.btn-outline-primary.dropdown-toggle:hover{color:#fff;background-color:#1789db;border-color:#1371b6}.btn-outline-primary.disabled.focus,.btn-outline-primary.disabled:focus,.btn-outline-primary.disabled:hover,.btn-outline-primary:disabled.focus,.btn-outline-primary:disabled:focus,.btn-outline-primary:disabled:hover{border-color:#b6dcf8}.btn-outline-secondary{color:#c5c5c5;background-image:none;background-color:transparent;border-color:#c5c5c5}.btn-outline-secondary.active,.btn-outline-secondary.focus,.btn-outline-secondary:active,.btn-outline-secondary:focus,.btn-outline-secondary:hover,.open>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#c5c5c5;border-color:#c5c5c5}.btn-outline-secondary.active.focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.active:hover,.btn-outline-secondary:active.focus,.btn-outline-secondary:active:focus,.btn-outline-secondary:active:hover,.open>.btn-outline-secondary.dropdown-toggle.focus,.open>.btn-outline-secondary.dropdown-toggle:focus,.open>.btn-outline-secondary.dropdown-toggle:hover{color:#fff;background-color:#9a9a9a;border-color:#858585}.btn-outline-secondary.disabled.focus,.btn-outline-secondary.disabled:focus,.btn-outline-secondary.disabled:hover,.btn-outline-secondary:disabled.focus,.btn-outline-secondary:disabled:focus,.btn-outline-secondary:disabled:hover{border-color:#f8f8f8}.btn-outline-info{color:#8d8d8d;background-image:none;background-color:transparent;border-color:#8d8d8d}.btn-outline-info.active,.btn-outline-info.focus,.btn-outline-info:active,.btn-outline-info:focus,.btn-outline-info:hover,.open>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#8d8d8d;border-color:#8d8d8d}.btn-outline-info.active.focus,.btn-outline-info.active:focus,.btn-outline-info.active:hover,.btn-outline-info:active.focus,.btn-outline-info:active:focus,.btn-outline-info:active:hover,.open>.btn-outline-info.dropdown-toggle.focus,.open>.btn-outline-info.dropdown-toggle:focus,.open>.btn-outline-info.dropdown-toggle:hover{color:#fff;background-color:#626262;border-color:#4d4d4d}.btn-outline-info.disabled.focus,.btn-outline-info.disabled:focus,.btn-outline-info.disabled:hover,.btn-outline-info:disabled.focus,.btn-outline-info:disabled:focus,.btn-outline-info:disabled:hover{border-color:silver}.btn-outline-success{color:#fb5000;background-image:none;background-color:transparent;border-color:#fb5000}.btn-outline-success.active,.btn-outline-success.focus,.btn-outline-success:active,.btn-outline-success:focus,.btn-outline-success:hover,.open>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#fb5000;border-color:#fb5000}.btn-outline-success.active.focus,.btn-outline-success.active:focus,.btn-outline-success.active:hover,.btn-outline-success:active.focus,.btn-outline-success:active:focus,.btn-outline-success:active:hover,.open>.btn-outline-success.dropdown-toggle.focus,.open>.btn-outline-success.dropdown-toggle:focus,.open>.btn-outline-success.dropdown-toggle:hover{color:#fff;background-color:#a43400;border-color:#7c2700}.btn-outline-success.disabled.focus,.btn-outline-success.disabled:focus,.btn-outline-success.disabled:hover,.btn-outline-success:disabled.focus,.btn-outline-success:disabled:focus,.btn-outline-success:disabled:hover{border-color:#ff9462}.btn-outline-warning{color:#fac13a;background-image:none;background-color:transparent;border-color:#fac13a}.btn-outline-warning.active,.btn-outline-warning.focus,.btn-outline-warning:active,.btn-outline-warning:focus,.btn-outline-warning:hover,.open>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#fac13a;border-color:#fac13a}.btn-outline-warning.active.focus,.btn-outline-warning.active:focus,.btn-outline-warning.active:hover,.btn-outline-warning:active.focus,.btn-outline-warning:active:focus,.btn-outline-warning:active:hover,.open>.btn-outline-warning.dropdown-toggle.focus,.open>.btn-outline-warning.dropdown-toggle:focus,.open>.btn-outline-warning.dropdown-toggle:hover{color:#fff;background-color:#d89905;border-color:#b07d04}.btn-outline-warning.disabled.focus,.btn-outline-warning.disabled:focus,.btn-outline-warning.disabled:hover,.btn-outline-warning:disabled.focus,.btn-outline-warning:disabled:focus,.btn-outline-warning:disabled:hover{border-color:#fde09d}.btn-outline-danger{color:#f33b2e;background-image:none;background-color:transparent;border-color:#f33b2e}.btn-outline-danger.active,.btn-outline-danger.focus,.btn-outline-danger:active,.btn-outline-danger:focus,.btn-outline-danger:hover,.open>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#f33b2e;border-color:#f33b2e}.btn-outline-danger.active.focus,.btn-outline-danger.active:focus,.btn-outline-danger.active:hover,.btn-outline-danger:active.focus,.btn-outline-danger:active:focus,.btn-outline-danger:active:hover,.open>.btn-outline-danger.dropdown-toggle.focus,.open>.btn-outline-danger.dropdown-toggle:focus,.open>.btn-outline-danger.dropdown-toggle:hover{color:#fff;background-color:#bf170b;border-color:#991209}.btn-outline-danger.disabled.focus,.btn-outline-danger.disabled:focus,.btn-outline-danger.disabled:hover,.btn-outline-danger:disabled.focus,.btn-outline-danger:disabled:focus,.btn-outline-danger:disabled:hover{border-color:#f9958e}.btn-link{color:#5ab0ee;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link:disabled{background-color:transparent}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#178ee4;text-decoration:underline;background-color:transparent}.btn-link:disabled:focus,.btn-link:disabled:hover{color:#c5c5c5;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:4px}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;border-radius:4px}.btn-block{display:block}.btn-block+.btn-block{margin-top:.5rem}.fade{opacity:0;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{height:0;transition-timing-function:ease;transition-duration:.35s;transition-property:height}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.3em;vertical-align:middle;border-top:.3em solid;border-right:.3em solid transparent;border-left:.3em solid transparent}.dropdown-toggle:focus{outline:0}.dropup .dropdown-toggle::after{border-top:0;border-bottom:.3em solid}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#454545;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:4px}.dropdown-divider{height:1px;margin:.5rem 0;overflow:hidden;background-color:#e5e5e5}.dropdown-item{display:block;width:100%;padding:3px 1.5rem;clear:both;color:#454545;text-align:inherit;background:0 0;border:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group-vertical>.btn:not(:first-child):not(:last-child),.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn,.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle),.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.dropdown-item:focus,.dropdown-item:hover{color:#383838;text-decoration:none;background-color:#f5f5f5}.dropdown-item.active,.dropdown-item.active:focus,.dropdown-item.active:hover{color:#454545;text-decoration:none;background-color:#e6e6e6;outline:0}.dropdown-item.disabled,.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{color:#c5c5c5}.dropdown-item.disabled:focus,.dropdown-item.disabled:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:"progid:DXImageTransform.Microsoft.gradient(enabled = false)"}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#c5c5c5}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:.3em solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:.125rem}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left;margin-bottom:0}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-15px}.btn-toolbar::after{display:table;clear:both}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:15px}.btn .caret,.btn+.dropdown-toggle-split::after,.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn+.dropdown-toggle-split{padding-right:11.25px;padding-left:11.25px}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:1.125rem;padding-left:1.125rem}.btn-group-lg>.btn .caret,.btn-lg .caret{border-width:.3em .3em 0}.dropup .btn-group-lg>.btn .caret,.dropup .btn-lg .caret{border-width:0 .3em .3em}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group::after{display:table;clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.custom-control,.input-group,.input-group-btn,.input-group-btn>.btn{position:relative}.input-group{width:100%;display:flex}.input-group .form-control{position:relative;z-index:2;flex:1;margin-bottom:0}.input-group .form-control:active,.input-group .form-control:focus,.input-group .form-control:hover,.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:3}.input-group-addon,.input-group-btn{white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 15px;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.25;color:#454545;text-align:center;background-color:#e6e6e6;border:1px solid #c5c5c5;border-radius:2px}.alert-link,.close,.tag{font-weight:700}.input-group-addon.form-control-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:4px}.input-group-addon.form-control-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:.75rem 1.5rem;font-size:1.25rem;border-radius:4px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:not(:last-child),.input-group-addon:not(:last-child),.input-group-btn:not(:first-child)>.btn-group:not(:last-child)>.btn,.input-group-btn:not(:first-child)>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group>.btn,.input-group-btn:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:not(:last-child){border-right:0}.input-group .form-control:not(:first-child),.input-group-addon:not(:first-child),.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group>.btn,.input-group-btn:not(:first-child)>.dropdown-toggle,.input-group-btn:not(:last-child)>.btn-group:not(:first-child)>.btn,.input-group-btn:not(:last-child)>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.form-control+.input-group-addon:not(:first-child){border-left:0}.input-group-btn{font-size:0}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn:not(:last-child)>.btn,.input-group-btn:not(:last-child)>.btn-group{margin-right:-1px}.input-group-btn:not(:first-child)>.btn,.input-group-btn:not(:first-child)>.btn-group{z-index:2;margin-left:-1px}.input-group-btn:not(:first-child)>.btn-group:active,.input-group-btn:not(:first-child)>.btn-group:focus,.input-group-btn:not(:first-child)>.btn-group:hover,.input-group-btn:not(:first-child)>.btn:active,.input-group-btn:not(:first-child)>.btn:focus,.input-group-btn:not(:first-child)>.btn:hover{z-index:3}.custom-control{display:inline-block;padding-left:1.5rem;cursor:pointer}.custom-control+.custom-control{margin-left:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-indicator{color:#fff;background-color:#0074d9}.custom-control-input:focus~.custom-control-indicator{box-shadow:0 0 0 .075rem #fff,0 0 0 .2rem #0074d9}.custom-control-input:active~.custom-control-indicator{color:#fff;background-color:#84c6ff}.custom-control-input:disabled~.custom-control-indicator{cursor:not-allowed;background-color:#eee}.custom-control-input:disabled~.custom-control-description{color:#767676;cursor:not-allowed}.custom-control-indicator{position:absolute;top:.25rem;left:0;display:block;width:1rem;height:1rem;pointer-events:none;user-select:none;background-color:#ddd;background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-file,.custom-select{display:inline-block;max-width:100%}.custom-checkbox .custom-control-indicator{border-radius:4px}.custom-checkbox .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='#fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3E%3C/svg%3E")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-indicator{background-color:#0074d9;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3E%3Cpath stroke='#fff' d='M0 2h4'/%3E%3C/svg%3E")}.custom-radio .custom-control-indicator{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-indicator{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#fff'/%3E%3C/svg%3E")}.custom-controls-stacked .custom-control{float:left;clear:left}.custom-controls-stacked .custom-control+.custom-control{margin-left:0}.custom-select{padding:6px 30px 6px 15px;padding-right:15px\9;color:#454545;vertical-align:middle;background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMiAyOCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1heFlNaWQiPjxwb2x5Z29uIHBvaW50cz0iMC4xLDEyLjIgNC41LDE2LjcgOSwxMi4yIi8+PC9zdmc+) right 15px center no-repeat #fff;background-image:none\9;background-size:auto auto;border:1px solid #c5c5c5;border-radius:2px;-moz-appearance:none}.custom-select:focus{border-color:#pstg-blue;outline:0}.custom-select:focus::-ms-value{color:#454545;background-color:#fff}.custom-select:disabled{color:#c5c5c5;cursor:not-allowed;background-color:#e6e6e6}.custom-select::-ms-expand{opacity:0}.custom-select-sm{padding-top:6px;padding-bottom:6px;font-size:75%}.custom-file{position:relative;height:2.5rem;cursor:pointer}.custom-file-control,.custom-file-control::before{position:absolute;height:2.5rem;padding:.5rem 1rem;line-height:1.5;color:#555}.custom-file-input{min-width:14rem;max-width:100%;margin:0;filter:alpha(opacity=0);opacity:0}.custom-file-control{top:0;right:0;left:0;z-index:5;user-select:none;background-color:#fff;border:1px solid #ddd;border-radius:4px}.custom-file-control:lang(en)::after{content:"Choose file..."}.custom-file-control::before{top:-1px;right:-1px;bottom:-1px;z-index:6;display:block;background-color:#eee;border:1px solid #ddd;border-radius:0 4px 4px 0}.nav-inline .nav-item,.nav-link{display:inline-block}.custom-file-control:lang(en)::before{content:"Browse"}.nav-pills::after,.nav-tabs::after,.navbar::after{content:"";clear:both}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#c5c5c5}.nav-link.disabled,.nav-link.disabled:focus,.nav-link.disabled:hover{color:#c5c5c5;cursor:not-allowed;background-color:transparent}.nav-inline .nav-item+.nav-item,.nav-inline .nav-link+.nav-link{margin-left:1rem}.nav-pills .nav-item+.nav-item,.nav-tabs .nav-item+.nav-item{margin-left:.2rem}.nav-tabs::after{display:table}.nav-tabs .nav-item{margin-bottom:0}.nav-tabs .nav-link{display:block;padding:.5em 1em;border:0 solid transparent;border-top-right-radius:0;border-top-left-radius:0}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e6e6e6 #e6e6e6 #ddd}.nav-tabs .nav-link.disabled,.nav-tabs .nav-link.disabled:focus,.nav-tabs .nav-link.disabled:hover{color:#c5c5c5;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.open .nav-link,.nav-tabs .nav-item.open .nav-link:focus,.nav-tabs .nav-item.open .nav-link:hover,.nav-tabs .nav-link.active,.nav-tabs .nav-link.active:focus,.nav-tabs .nav-link.active:hover{color:#8d8d8d;background-color:#e6e6e6;border-color:#ddd #ddd transparent}.nav-tabs .dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.nav-pills::after{display:table}.nav-pills .nav-item{float:left}.nav-pills .nav-link{display:block;padding:.5em 1em;border-radius:4px}.nav-pills .nav-item.open .nav-link,.nav-pills .nav-item.open .nav-link:focus,.nav-pills .nav-item.open .nav-link:hover,.nav-pills .nav-link.active,.nav-pills .nav-link.active:focus,.nav-pills .nav-link.active:hover{color:#454545;cursor:default;background-color:#e6e6e6}.nav-stacked .nav-item{display:block;float:none}.nav-stacked .nav-item+.nav-item{margin-top:.2rem;margin-left:0}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;padding:0}.navbar::after{display:table}.navbar-full{z-index:1000}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar-sticky-top{position:sticky;top:0;z-index:1030;width:100%}@media (min-width:576px){.navbar{border-radius:4px}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-full,.navbar-sticky-top{border-radius:0}}.navbar-brand{float:left;padding-top:.25rem;padding-bottom:.25rem;margin-right:1rem;font-size:1.25rem;line-height:inherit}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-divider{float:left;width:1px;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0}.navbar-divider::before{content:"\00a0"}.navbar-toggleable-lg::after,.navbar-toggleable-md::after,.navbar-toggleable-sm::after,.navbar-toggleable-xl::after,.navbar-toggleable-xs::after{content:"";clear:both}.navbar-text{display:inline-block;padding-top:.425rem;padding-bottom:.425rem}.navbar-toggler{width:2.5em;height:2em;padding:.5rem .75rem;font-size:1.25rem;line-height:1;background:center center no-repeat;background-size:24px 24px;border:1px solid transparent;border-radius:2px}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}@media (max-width:575px){.navbar-toggleable-xs .navbar-brand{display:block;float:none;margin-top:.5rem;margin-right:0}.navbar-toggleable-xs .navbar-nav{margin-top:.5rem;margin-bottom:.5rem}.navbar-toggleable-xs .navbar-nav .dropdown-menu{position:static;float:none}}@media (min-width:576px){.navbar-toggleable-xs{display:block}}@media (max-width:767px){.navbar-toggleable-sm .navbar-brand{display:block;float:none;margin-top:.5rem;margin-right:0}.navbar-toggleable-sm .navbar-nav{margin-top:.5rem;margin-bottom:.5rem}.navbar-toggleable-sm .navbar-nav .dropdown-menu{position:static;float:none}}@media (min-width:768px){.navbar-toggleable-sm{display:block}}@media (max-width:991px){.navbar-toggleable-md .navbar-brand{display:block;float:none;margin-top:.5rem;margin-right:0}.navbar-toggleable-md .navbar-nav{margin-top:.5rem;margin-bottom:.5rem}.navbar-toggleable-md .navbar-nav .dropdown-menu{position:static;float:none}}@media (min-width:992px){.navbar-toggleable-md{display:block}}.navbar-toggleable-lg::after{display:table}@media (max-width:1199px){.navbar-toggleable-lg .navbar-brand{display:block;float:none;margin-top:.5rem;margin-right:0}.navbar-toggleable-lg .navbar-nav{margin-top:.5rem;margin-bottom:.5rem}.navbar-toggleable-lg .navbar-nav .dropdown-menu{position:static;float:none}}@media (min-width:1200px){.navbar-toggleable-lg{display:block}}.navbar-toggleable-xl{display:block}.navbar-toggleable-xl::after{display:table}.navbar-toggleable-xl .navbar-brand{display:block;float:none;margin-top:.5rem;margin-right:0}.navbar-toggleable-xl .navbar-nav{margin-top:.5rem;margin-bottom:.5rem}.card,.card-title{margin-bottom:5px}.navbar-toggleable-xl .navbar-nav .dropdown-menu{position:static;float:none}.navbar-nav .nav-item{float:left}.navbar-nav .nav-link{display:block;padding-top:.425rem;padding-bottom:.425rem}.navbar-nav .nav-item+.nav-item,.navbar-nav .nav-link+.nav-link{margin-left:1rem}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover,.navbar-light .navbar-toggler,.navbar-light .navbar-toggler:focus,.navbar-light .navbar-toggler:hover{color:#454545}.navbar-light .navbar-nav .nav-link{color:#8d8d8d}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .active>.nav-link:focus,.navbar-light .navbar-nav .active>.nav-link:hover,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.active:focus,.navbar-light .navbar-nav .nav-link.active:hover,.navbar-light .navbar-nav .nav-link.open,.navbar-light .navbar-nav .nav-link.open:focus,.navbar-light .navbar-nav .nav-link.open:hover,.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .open>.nav-link,.navbar-light .navbar-nav .open>.nav-link:focus,.navbar-light .navbar-nav .open>.nav-link:hover{color:#454545}.navbar-light .navbar-toggler{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='#8d8d8d' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E");border-color:rgba(0,0,0,.1)}.navbar-light .navbar-divider{background-color:rgba(0,0,0,.075)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-toggler,.navbar-dark .navbar-toggler:focus,.navbar-dark .navbar-toggler:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.card-inverse .card-blockquote,.card-inverse .card-footer,.card-inverse .card-header,.card-inverse .card-title,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .active>.nav-link:focus,.navbar-dark .navbar-nav .active>.nav-link:hover,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.active:focus,.navbar-dark .navbar-nav .nav-link.active:hover,.navbar-dark .navbar-nav .nav-link.open,.navbar-dark .navbar-nav .nav-link.open:focus,.navbar-dark .navbar-nav .nav-link.open:hover,.navbar-dark .navbar-nav .open>.nav-link,.navbar-dark .navbar-nav .open>.nav-link:focus,.navbar-dark .navbar-nav .open>.nav-link:hover{color:#fff}.navbar-dark .navbar-toggler{background-image:url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E");border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-divider{background-color:rgba(255,255,255,.075)}.navbar-toggleable-xs::after{display:table}@media (max-width:575px){.navbar-toggleable-xs .navbar-nav .nav-item{float:none;margin-left:0}}@media (min-width:576px){.navbar-toggleable-xs{display:block!important}}.navbar-toggleable-sm::after{display:table}@media (max-width:767px){.navbar-toggleable-sm .navbar-nav .nav-item{float:none;margin-left:0}}@media (min-width:768px){.navbar-toggleable-sm{display:block!important}}.navbar-toggleable-md::after{display:table}@media (max-width:991px){.navbar-toggleable-md .navbar-nav .nav-item{float:none;margin-left:0}}.breadcrumb-item,.page-link{float:left}@media (min-width:992px){.navbar-toggleable-md{display:block!important}}.card{position:relative;display:block;background-color:#fff;border-radius:4px;border:1px solid #c5c5c5}.card-block::after,.card-footer::after,.card-header::after{display:table;content:"";clear:both}.card-block{padding:20px}.card-footer,.card-header{padding:5px 20px;background-color:#f5f5f5}.card-header,.card-subtitle,.card-text:last-child{margin-bottom:0}.card-subtitle{margin-top:-2.5px}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:20px}.card-header-pills,.card-header-tabs{margin-right:-10px;margin-left:-10px}.card>.list-group:first-child .list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.card-header{border-bottom:1px solid #c5c5c5}.card-header:first-child{border-radius:calc(4px - 1px) calc(4px - 1px) 0 0}.card-footer{border-top:1px solid #c5c5c5}.card-footer:last-child{border-radius:0 0 calc(4px - 1px) calc(4px - 1px)}.card-header-tabs{margin-bottom:-5px;border-bottom:0}.card-primary{background-color:#5ab0ee;border-color:#5ab0ee}.card-primary .card-footer,.card-primary .card-header{background-color:transparent}.card-success{background-color:#71a74f;border-color:#71a74f}.card-success .card-footer,.card-success .card-header{background-color:transparent}.card-info{background-color:#5bc0de;border-color:#5bc0de}.card-info .card-footer,.card-info .card-header{background-color:transparent}.card-warning{background-color:#fac13a;border-color:#fac13a}.card-warning .card-footer,.card-warning .card-header{background-color:transparent}.card-danger{background-color:#f33b2e;border-color:#f33b2e}.card-danger .card-footer,.card-danger .card-header,.card-outline-danger,.card-outline-info,.card-outline-primary,.card-outline-secondary,.card-outline-success,.card-outline-warning{background-color:transparent}.card-outline-primary{border-color:#5ab0ee}.card-outline-secondary{border-color:#c5c5c5}.card-outline-info{border-color:#8d8d8d}.card-outline-success{border-color:#fb5000}.card-outline-warning{border-color:#fac13a}.card-outline-danger{border-color:#f33b2e}.card-inverse .card-footer,.card-inverse .card-header{border-color:rgba(255,255,255,.2)}.card-inverse .card-blockquote .blockquote-footer,.card-inverse .card-link,.card-inverse .card-subtitle,.card-inverse .card-text{color:rgba(255,255,255,.65)}.card-inverse .card-link:focus,.card-inverse .card-link:hover{color:#fff}.card-blockquote{padding:0;margin-bottom:0;border-left:0}.card-img{border-radius:calc(4px - 1px)}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img-top{border-top-right-radius:calc(4px - 1px);border-top-left-radius:calc(4px - 1px)}.card-img-bottom{border-bottom-right-radius:calc(4px - 1px);border-bottom-left-radius:calc(4px - 1px)}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap;margin-right:-.625rem;margin-bottom:5px;margin-left:-.625rem}.card-deck .card{flex:1 0 0;margin-right:.625rem;margin-bottom:0;margin-left:.625rem}.card-group{display:flex;flex-flow:row wrap}.card-group .card{flex:1 0 0}.card-group .card+.card{margin-left:0;border-left:0}.card-group .card:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.card-group .card:first-child .card-img-top{border-top-right-radius:0}.card-group .card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group .card:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.card-group .card:last-child .card-img-top{border-top-left-radius:0}.card-group .card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group .card:not(:first-child):not(:last-child),.card-group .card:not(:first-child):not(:last-child) .card-img-bottom,.card-group .card:not(:first-child):not(:last-child) .card-img-top{border-radius:0}.card-columns{column-count:3;column-gap:1.25rem}.card-columns .card{display:inline-block;width:100%}}.breadcrumb,.pagination{margin-bottom:1rem;border-radius:4px}.breadcrumb{padding:.75rem 1rem;list-style:none;background-color:#e6e6e6}.breadcrumb::after{content:"";display:table;clear:both}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;padding-left:.5rem;color:#c5c5c5;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#c5c5c5}.pagination{display:inline-block;padding-left:0;margin-top:1rem}.page-item{display:inline}.page-item:first-child .page-link{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.page-item:last-child .page-link{border-bottom-right-radius:4px;border-top-right-radius:4px}.page-item.active .page-link,.page-item.active .page-link:focus,.page-item.active .page-link:hover{z-index:2;color:#fff;cursor:default;background-color:#5ab0ee;border-color:#5ab0ee}.page-item.disabled .page-link,.page-item.disabled .page-link:focus,.page-item.disabled .page-link:hover{color:#c5c5c5;pointer-events:none;cursor:not-allowed;background-color:#fff;border-color:#ddd}.page-link{position:relative;padding:.5rem .75rem;margin-left:-1px;color:#5ab0ee;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination-lg .page-item:first-child .page-link,.pagination-sm .page-item:first-child .page-link{border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination-lg .page-item:last-child .page-link,.pagination-sm .page-item:last-child .page-link{border-bottom-right-radius:4px;border-top-right-radius:4px}.page-link:focus,.page-link:hover{color:#178ee4;background-color:#e6e6e6;border-color:#ddd}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-sm .page-link{padding:.275rem .75rem;font-size:.875rem}.tag{display:inline-block;padding:.25em .4em;font-size:75%;line-height:1;color:#fff;text-align:center;vertical-align:baseline;border-radius:4px}.tag:empty{display:none}.btn .tag{position:relative;top:-1px}a.tag:focus,a.tag:hover{color:#fff;text-decoration:none;cursor:pointer}.tag-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.tag-default{background-color:#c5c5c5}.tag-default[href]:focus,.tag-default[href]:hover{background-color:#acacac}.tag-primary{background-color:#5ab0ee}.tag-primary[href]:focus,.tag-primary[href]:hover{background-color:#2c9ae9}.tag-success{background-color:#71a74f}.tag-success[href]:focus,.tag-success[href]:hover{background-color:#5a843f}.tag-info{background-color:#5bc0de}.tag-info[href]:focus,.tag-info[href]:hover{background-color:#31b0d5}.tag-warning{background-color:#fac13a}.tag-warning[href]:focus,.tag-warning[href]:hover{background-color:#f9b108}.tag-danger{background-color:#f33b2e}.tag-danger[href]:focus,.tag-danger[href]:hover{background-color:#e11b0d}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e6e6e6;border-radius:4px}.alert,.progress{margin-bottom:1rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-hr{border-top-color:#cdcdcd}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{padding:.75rem 1.25rem;border:1px solid transparent;border-radius:4px}.alert-heading{color:inherit}.alert-dismissible{padding-right:2.5rem}.alert-dismissible .close{position:relative;top:-.125rem;right:-1.25rem;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d0e9c6;color:#3c763d}.alert-success hr{border-top-color:#c1e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bcdff1;color:#31708f}.alert-info hr{border-top-color:#a6d5ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faf2cc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7ecb5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebcccc;color:#a94442}.alert-danger hr{border-top-color:#e4b9b9}.alert-danger .alert-link{color:#843534}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:block;width:100%;height:1rem}.progress[value]{background-color:#eee;border:0;appearance:none;border-radius:4px}.progress[value]::-ms-fill{background-color:#0074d9;border:0}.progress[value]::-moz-progress-bar{background-color:#0074d9;border-bottom-left-radius:4px;border-top-left-radius:4px}.progress[value]::-webkit-progress-value{background-color:#0074d9;border-bottom-left-radius:4px;border-top-left-radius:4px}.progress[value="100"]::-moz-progress-bar{border-bottom-right-radius:4px;border-top-right-radius:4px}.progress[value="100"]::-webkit-progress-value{border-bottom-right-radius:4px;border-top-right-radius:4px}.progress[value]::-webkit-progress-bar{background-color:#eee;border-radius:4px}.progress[value],base::-moz-progress-bar{background-color:#eee;border-radius:4px}.progress-striped[value]::-webkit-progress-value{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-striped[value]::-moz-progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-striped[value]::-ms-fill{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-animated[value]::-webkit-progress-value{animation:progress-bar-stripes 2s linear infinite}.progress-animated[value]::-moz-progress-bar{animation:progress-bar-stripes 2s linear infinite}@media screen and (min-width:0\0){.progress{background-color:#eee;border-radius:4px}.progress-bar{display:inline-block;height:1rem;text-indent:-999rem;background-color:#0074d9;border-bottom-left-radius:4px;border-top-left-radius:4px}.progress[width="100%"]{border-bottom-right-radius:4px;border-top-right-radius:4px}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-animated .progress-bar-striped{animation:progress-bar-stripes 2s linear infinite}.progress-success .progress-bar{background-color:#71a74f}}.progress-success[value]::-webkit-progress-value{background-color:#71a74f}.progress-success[value]::-moz-progress-bar{background-color:#71a74f}.progress-success[value]::-ms-fill{background-color:#71a74f}.progress-info[value]::-webkit-progress-value{background-color:#5bc0de}.progress-info[value]::-moz-progress-bar{background-color:#5bc0de}.progress-info[value]::-ms-fill{background-color:#5bc0de}@media screen and (min-width:0\0){.progress-info .progress-bar{background-color:#5bc0de}.progress-warning .progress-bar{background-color:#fac13a}}.progress-warning[value]::-webkit-progress-value{background-color:#fac13a}.progress-warning[value]::-moz-progress-bar{background-color:#fac13a}.progress-warning[value]::-ms-fill{background-color:#fac13a}.progress-danger[value]::-webkit-progress-value{background-color:#f33b2e}.progress-danger[value]::-moz-progress-bar{background-color:#f33b2e}.progress-danger[value]::-ms-fill{background-color:#f33b2e}@media screen and (min-width:0\0){.progress-danger .progress-bar{background-color:#f33b2e}}.media{display:flex}.media-body{flex:1}.media-middle{align-self:center}.media-bottom{align-self:flex-end}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right{padding-left:10px}.media-left{padding-right:10px}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:0}.list-group-item{position:relative;display:block;padding:20px;margin-bottom:-1px;background-color:#fff;border:1px solid #c5c5c5}.list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.list-group-item.disabled,.list-group-item.disabled:focus{color:#c5c5c5;cursor:not-allowed;background-color:#e6e6e6}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#c5c5c5}.list-group-item.disabled:hover{color:#c5c5c5;cursor:not-allowed;background-color:#e6e6e6}.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled:hover .list-group-item-text{color:#c5c5c5}.list-group-item.active,.list-group-item.active:focus{z-index:2;color:#454545;text-decoration:none;background-color:#e6e6e6;border-color:#e6e6e6}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#fff}.list-group-item.active:hover{z-index:2;color:#454545;text-decoration:none;background-color:#e6e6e6;border-color:#e6e6e6}.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active:hover .list-group-item-text{color:#fff}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-item-action{width:100%;color:#555;text-align:inherit;cursor:pointer}.list-group-item-action .list-group-item-heading{color:#333}.list-group-item-action:focus,.list-group-item-action:hover{color:#555;text-decoration:none;background-color:#f7f7f7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.embed-responsive{position:relative;display:block;height:0;padding:0}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9{padding-bottom:42.85714%}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.embed-responsive-1by1{padding-bottom:100%}.close{float:right;font-size:1.5rem;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2}.popover,.tooltip{font-family:"Proxima Nova",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-style:normal;letter-spacing:normal;line-break:auto;line-height:1.5;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;font-size:.875rem;word-wrap:break-word;text-decoration:none;font-weight:400}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-content,.popover{background-clip:padding-box}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;outline:0}.modal-footer::after,.modal-header::after{display:table;content:"";clear:both}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-25%)}.modal.in .modal-dialog{transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:4px;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.in{opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.5}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.popover,.tooltip{display:block;position:absolute}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:600px;margin:30px auto}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg{max-width:900px}}.tooltip{z-index:1070;text-align:left;text-align:start;opacity:0}.tooltip.in{opacity:.9}.tooltip.bs-tether-element-attached-bottom,.tooltip.tooltip-top{padding:5px 0;margin-top:-3px}.tooltip.bs-tether-element-attached-bottom .tooltip-inner::before,.tooltip.tooltip-top .tooltip-inner::before{bottom:0;left:50%;margin-left:-5px;content:"";border-width:5px 5px 0;border-top-color:#222}.tooltip.bs-tether-element-attached-left,.tooltip.tooltip-right{padding:0 5px;margin-left:3px}.tooltip.bs-tether-element-attached-left .tooltip-inner::before,.tooltip.tooltip-right .tooltip-inner::before{top:50%;left:0;margin-top:-5px;content:"";border-width:5px 5px 5px 0;border-right-color:#222}.tooltip.bs-tether-element-attached-top,.tooltip.tooltip-bottom{padding:5px 0;margin-top:3px}.tooltip.bs-tether-element-attached-top .tooltip-inner::before,.tooltip.tooltip-bottom .tooltip-inner::before{top:0;left:50%;margin-left:-5px;content:"";border-width:0 5px 5px;border-bottom-color:#222}.tooltip.bs-tether-element-attached-right,.tooltip.tooltip-left{padding:0 5px;margin-left:-3px}.tooltip.bs-tether-element-attached-right .tooltip-inner::before,.tooltip.tooltip-left .tooltip-inner::before{top:50%;right:0;margin-top:-5px;content:"";border-width:5px 0 5px 5px;border-left-color:#222}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#222;border-radius:4px}.tooltip-inner::before{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{top:0;left:0;z-index:1060;max-width:276px;padding:1px;text-align:left;text-align:start;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:4px}.carousel-caption,.carousel-control{color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.popover.bs-tether-element-attached-bottom,.popover.popover-top{margin-top:-10px}.popover.bs-tether-element-attached-bottom::after,.popover.bs-tether-element-attached-bottom::before,.popover.popover-top::after,.popover.popover-top::before{left:50%;border-bottom-width:0}.popover.bs-tether-element-attached-bottom::before,.popover.popover-top::before{bottom:-11px;margin-left:-11px;border-top-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-bottom::after,.popover.popover-top::after{bottom:-10px;margin-left:-10px;border-top-color:#fff}.popover.bs-tether-element-attached-left,.popover.popover-right{margin-left:10px}.popover.bs-tether-element-attached-left::after,.popover.bs-tether-element-attached-left::before,.popover.popover-right::after,.popover.popover-right::before{top:50%;border-left-width:0}.popover.bs-tether-element-attached-left::before,.popover.popover-right::before{left:-11px;margin-top:-11px;border-right-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-left::after,.popover.popover-right::after{left:-10px;margin-top:-10px;border-right-color:#fff}.popover.bs-tether-element-attached-top,.popover.popover-bottom{margin-top:10px}.popover.bs-tether-element-attached-top::after,.popover.bs-tether-element-attached-top::before,.popover.popover-bottom::after,.popover.popover-bottom::before{left:50%;border-top-width:0}.popover.bs-tether-element-attached-top::before,.popover.popover-bottom::before{top:-11px;margin-left:-11px;border-bottom-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-top::after,.popover.popover-bottom::after{top:-10px;margin-left:-10px;border-bottom-color:#f7f7f7}.popover.bs-tether-element-attached-top .popover-title::before,.popover.popover-bottom .popover-title::before{position:absolute;top:0;left:50%;display:block;width:20px;margin-left:-10px;content:"";border-bottom:1px solid #f7f7f7}.popover.bs-tether-element-attached-right,.popover.popover-left{margin-left:-10px}.popover.bs-tether-element-attached-right::after,.popover.bs-tether-element-attached-right::before,.popover.popover-left::after,.popover.popover-left::before{top:50%;border-right-width:0}.popover.bs-tether-element-attached-right::before,.popover.popover-left::before{right:-11px;margin-top:-11px;border-left-color:rgba(0,0,0,.25)}.popover.bs-tether-element-attached-right::after,.popover.popover-left::after{right:-10px;margin-top:-10px;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:3.92px 3.92px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover::after,.popover::before{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.carousel,.carousel-inner{position:relative}.popover::before{content:"";border-width:11px}.popover::after{content:"";border-width:10px}.carousel-inner{width:100%;overflow:hidden}.carousel-inner>.carousel-item{position:relative;display:none;transition:.6s ease-in-out left}.carousel-inner>.carousel-item>a>img,.carousel-inner>.carousel-item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.carousel-item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:1000px}.carousel-inner>.carousel-item.active.right,.carousel-inner>.carousel-item.next{left:0;transform:translate3d(100%,0,0)}.carousel-inner>.carousel-item.active.left,.carousel-inner>.carousel-item.prev{left:0;transform:translate3d(-100%,0,0)}.carousel-inner>.carousel-item.active,.carousel-inner>.carousel-item.next.left,.carousel-inner>.carousel-item.prev.right{left:0;transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;opacity:.5}.carousel-control.left{background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;width:20px;height:20px;margin-top:-10px;font-family:serif;line-height:1}.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-prev::before{content:"\2039"}.carousel-control .icon-next::before{content:"\203a"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:transparent;border:1px solid #fff;border-radius:10px}.rounded-right,.rounded-top{border-top-right-radius:4px}.rounded-bottom,.rounded-right{border-bottom-right-radius:4px}.rounded-bottom,.rounded-left{border-bottom-left-radius:4px}.rounded-left,.rounded-top{border-top-left-radius:4px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px}.carousel-caption .btn,.text-hide{text-shadow:none}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-faded{background-color:#f7f7f7}.bg-primary{background-color:#5ab0ee!important}a.bg-primary:focus,a.bg-primary:hover{background-color:#2c9ae9!important}.bg-success{background-color:#71a74f!important}a.bg-success:focus,a.bg-success:hover{background-color:#5a843f!important}.bg-info{background-color:#5bc0de!important}a.bg-info:focus,a.bg-info:hover{background-color:#31b0d5!important}.bg-warning{background-color:#fac13a!important}a.bg-warning:focus,a.bg-warning:hover{background-color:#f9b108!important}.bg-danger{background-color:#f33b2e!important}a.bg-danger:focus,a.bg-danger:hover{background-color:#e11b0d!important}.bg-inverse{background-color:#454545!important}a.bg-inverse:focus,a.bg-inverse:hover{background-color:#2c2c2c!important}.rounded{border-radius:4px}.rounded-circle{border-radius:50%}.clearfix::after{content:"";display:table;clear:both}.d-block{display:block!important}.d-inline-block{display:inline-block!important}.d-inline{display:inline!important}.hidden-xl-down,.hidden-xs-up,.visible-print-block{display:none!important}.flex-xs-first{order:-1}.flex-xs-last{order:1}.flex-xs-unordered{order:0}.flex-items-xs-top{align-items:flex-start}.flex-items-xs-middle{align-items:center}.flex-items-xs-bottom{align-items:flex-end}.flex-xs-top{align-self:flex-start}.flex-xs-middle{align-self:center}.flex-xs-bottom{align-self:flex-end}.flex-items-xs-left{justify-content:flex-start}.flex-items-xs-center{justify-content:center}.flex-items-xs-right{justify-content:flex-end}.flex-items-xs-around{justify-content:space-around}.flex-items-xs-between{justify-content:space-between}.float-xs-left{float:left!important}.float-xs-right{float:right!important}.float-xs-none{float:none!important}@media (min-width:576px){.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .icon-prev{margin-left:-15px}.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}.flex-sm-first{order:-1}.flex-sm-last{order:1}.flex-sm-unordered{order:0}.flex-items-sm-top{align-items:flex-start}.flex-items-sm-middle{align-items:center}.flex-items-sm-bottom{align-items:flex-end}.flex-sm-top{align-self:flex-start}.flex-sm-middle{align-self:center}.flex-sm-bottom{align-self:flex-end}.flex-items-sm-left{justify-content:flex-start}.flex-items-sm-center{justify-content:center}.flex-items-sm-right{justify-content:flex-end}.flex-items-sm-around{justify-content:space-around}.flex-items-sm-between{justify-content:space-between}.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.pr-0,.px-0{padding-right:0!important}.pl-0,.px-0{padding-left:0!important}.pt-0,.py-0{padding-top:0!important}.pb-0,.py-0{padding-bottom:0!important}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.mt-0,.my-0{margin-top:0!important}.mb-0,.my-0{margin-bottom:0!important}.w-100{width:100%!important}.h-100{height:100%!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.mr-0,.mx-0{margin-right:0!important}.ml-0,.mx-0{margin-left:0!important}.m-0{margin:0!important}.mr-1,.mx-1{margin-right:1rem!important}.ml-1,.mx-1{margin-left:1rem!important}.mt-1,.my-1{margin-top:1rem!important}.mb-1,.my-1{margin-bottom:1rem!important}.m-1{margin:1rem!important}.mr-2,.mx-2{margin-right:1.5rem!important}.ml-2,.mx-2{margin-left:1.5rem!important}.mt-2,.my-2{margin-top:1.5rem!important}.mb-2,.my-2{margin-bottom:1.5rem!important}.m-2{margin:1.5rem!important}.mr-3,.mx-3{margin-right:3rem!important}.ml-3,.mx-3{margin-left:3rem!important}.mt-3,.my-3{margin-top:3rem!important}.mb-3,.my-3{margin-bottom:3rem!important}.m-3{margin:3rem!important}.p-0{padding:0!important}.pr-1,.px-1{padding-right:1rem!important}.pl-1,.px-1{padding-left:1rem!important}.pt-1,.py-1{padding-top:1rem!important}.pb-1,.py-1{padding-bottom:1rem!important}.p-1{padding:1rem!important}.pr-2,.px-2{padding-right:1.5rem!important}.pl-2,.px-2{padding-left:1.5rem!important}.pt-2,.py-2{padding-top:1.5rem!important}.pb-2,.py-2{padding-bottom:1.5rem!important}.p-2{padding:1.5rem!important}.pr-3,.px-3{padding-right:3rem!important}.pl-3,.px-3{padding-left:3rem!important}.pt-3,.py-3{padding-top:3rem!important}.pb-3,.py-3{padding-bottom:3rem!important}.p-3{padding:3rem!important}.pos-f-t{position:fixed;top:0;right:0;left:0;z-index:1030}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-xs-left{text-align:left!important}.text-xs-right{text-align:right!important}.text-xs-center{text-align:center!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-normal{font-weight:400}.font-weight-bold{font-weight:700}.font-italic{font-style:italic}.text-white{color:#fff!important}.text-muted{color:#c5c5c5!important}a.text-muted:focus,a.text-muted:hover{color:#acacac!important}.text-primary{color:#5ab0ee!important}a.text-primary:focus,a.text-primary:hover{color:#2c9ae9!important}.text-success{color:#71a74f!important}a.text-success:focus,a.text-success:hover{color:#5a843f!important}.text-info{color:#5bc0de!important}a.text-info:focus,a.text-info:hover{color:#31b0d5!important}.text-warning{color:#fac13a!important}a.text-warning:focus,a.text-warning:hover{color:#f9b108!important}.text-danger{color:#f33b2e!important}a.text-danger:focus,a.text-danger:hover{color:#e11b0d!important}.text-gray-dark{color:#454545!important}a.text-gray-dark:focus,a.text-gray-dark:hover{color:#2c2c2c!important}.text-hide{font:0/0 a;color:transparent;background-color:transparent;border:0}.nav-tabs,.navbar.navbar-full{border-bottom:solid 1px #c5c5c5}.invisible{visibility:hidden!important}@media (max-width:575px){.hidden-xs-down{display:none!important}}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}.hidden-sm-up{display:none!important}}@media (max-width:767px){.hidden-sm-down{display:none!important}}@media (min-width:768px){.flex-md-first{order:-1}.flex-md-last{order:1}.flex-md-unordered{order:0}.flex-items-md-top{align-items:flex-start}.flex-items-md-middle{align-items:center}.flex-items-md-bottom{align-items:flex-end}.flex-md-top{align-self:flex-start}.flex-md-middle{align-self:center}.flex-md-bottom{align-self:flex-end}.flex-items-md-left{justify-content:flex-start}.flex-items-md-center{justify-content:center}.flex-items-md-right{justify-content:flex-end}.flex-items-md-around{justify-content:space-around}.flex-items-md-between{justify-content:space-between}.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}.hidden-md-up{display:none!important}}@media (max-width:991px){.hidden-md-down{display:none!important}}@media (min-width:992px){.flex-lg-first{order:-1}.flex-lg-last{order:1}.flex-lg-unordered{order:0}.flex-items-lg-top{align-items:flex-start}.flex-items-lg-middle{align-items:center}.flex-items-lg-bottom{align-items:flex-end}.flex-lg-top{align-self:flex-start}.flex-lg-middle{align-self:center}.flex-lg-bottom{align-self:flex-end}.flex-items-lg-left{justify-content:flex-start}.flex-items-lg-center{justify-content:center}.flex-items-lg-right{justify-content:flex-end}.flex-items-lg-around{justify-content:space-around}.flex-items-lg-between{justify-content:space-between}.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}.hidden-lg-up{display:none!important}}@media (max-width:1199px){.hidden-lg-down{display:none!important}}@media (min-width:1200px){.flex-xl-first{order:-1}.flex-xl-last{order:1}.flex-xl-unordered{order:0}.flex-items-xl-top{align-items:flex-start}.flex-items-xl-middle{align-items:center}.flex-items-xl-bottom{align-items:flex-end}.flex-xl-top{align-self:flex-start}.flex-xl-middle{align-self:center}.flex-xl-bottom{align-self:flex-end}.flex-items-xl-left{justify-content:flex-start}.flex-items-xl-center{justify-content:center}.flex-items-xl-right{justify-content:flex-end}.flex-items-xl-around{justify-content:space-around}.flex-items-xl-between{justify-content:space-between}.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}.hidden-xl-up{display:none!important}}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}.hidden-print{display:none!important}}.nav-item{position:relative;height:43px}.nav-item .nav-link{color:#8d8d8d;height:43px;line-height:43px;padding:0 20px;font-size:16px;font-weight:600}.card-header,.nav-item.active .nav-link{color:#454545}.card-header,.table thead th{font-size:15px}.nav-item.active .nav-link::after{content:'';display:block;position:absolute;left:18px;right:18px;bottom:0;height:4px;border-radius:2px;background-color:#fb5000}.nav-item:last-of-type .nav-link{padding-right:0}.nav-item:last-of-type.active .nav-link::after{right:-2px}.navbar.navbar-full{height:43px}.navbar.navbar-light{background-color:#fff}.nav-tabs{background-color:#f7f7f7}.nav-tabs .nav-item{display:inline-block;float:none}.tab-content .list-group .list-group-item{border-right:0;border-left:0;line-height:1.3;overflow-wrap:break-word}.card+.card{margin-top:20px}.card-header{font-weight:600;min-height:36px;overflow-wrap:break-word}.no-disabled-background.list-group .list-group-item.disabled{background-color:#fff}.table{background-color:transparent}.table tbody,.table tfoot,.table thead{background-color:#fff}.table thead tr:first-of-type th{border-top:0}.table.table-bordered{border-collapse:separate;border-spacing:0;border-radius:4px}.table.table-bordered td #list-view-array-name-cell{text-overflow:ellipsis;overflow:hidden;white-space:nowrap;max-width:100px}.table.table-bordered td,.table.table-bordered th{border-left:0;border-top:0;border-bottom:1px solid #ddd;border-right:1px solid #ddd}.table.table-bordered tr:last-of-type td{border-bottom:0}.table.table-bordered td:last-of-type,.table.table-bordered th:last-of-type{border-right:0}.table.table-bordered tr:first-of-type th:first-of-type{border-top-left-radius:3px}.table.table-bordered tr:first-of-type th:last-of-type{border-top-right-radius:3px}.table.table-bordered tr:last-of-type td:first-of-type{border-bottom-left-radius:3px}.table.table-bordered tr:last-of-type td:last-of-type{border-bottom-right-radius:3px}.table.table-bordered.not-first-col td:first-of-type,.table.table-bordered.not-first-col th:first-of-type{border-right:0;padding-right:0}.table .thead-default{background-color:#f7f7f7}.table .thead-default td,.table .thead-default th,.table .thead-default tr tr{font-size:15px;font-weight:600;color:#454545;background-color:transparent}.table.table-fixed-header{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;align-items:stretch}.table.table-fixed-header thead{display:flex;flex-direction:column;align-items:stretch;position:relative}.table.table-fixed-header td,.table.table-fixed-header tfoot,.table.table-fixed-header th,.table.table-fixed-header thead{flex-shrink:0}.table.table-fixed-header tbody{overflow-y:scroll;display:inline-block}.table.table-fixed-header tbody>tr,.table.table-fixed-header tfoot>tr,.table.table-fixed-header thead>tr{display:flex;flex-direction:row;flex-wrap:nowrap}.table.table-fixed-header tbody td,.table.table-fixed-header thead th{overflow-x:hidden;text-overflow:ellipsis;display:inline-block;white-space:nowrap}.table.table-fixed-header .weight-1,.table.table-fixed-header td,.table.table-fixed-header th{min-width:41px;width:41px;flex-grow:1;flex-shrink:0}.table.table-fixed-header .weight-2{min-width:82px;width:82px;flex-grow:2;flex-shrink:0}.table.table-fixed-header .weight-3{min-width:123px;width:123px;flex-grow:3;flex-shrink:0}.table.table-fixed-header .weight-4{min-width:164px;width:164px;flex-grow:4;flex-shrink:0}.table.table-fixed-header .weight-5{min-width:205px;width:205px;flex-grow:5;flex-shrink:0}.table.table-fixed-header .weight-6{min-width:246px;width:246px;flex-grow:6;flex-shrink:0}.table.table-fixed-header .weight-7{min-width:287px;width:287px;flex-grow:7;flex-shrink:0}.table.table-fixed-header .weight-8{min-width:328px;width:328px;flex-grow:8;flex-shrink:0}.table.table-fixed-header .weight-9{min-width:369px;width:369px;flex-grow:9;flex-shrink:0}.table.table-fixed-header .weight-10{min-width:410px;width:410px;flex-grow:10;flex-shrink:0}.table.table-fixed-header .weight-11{min-width:451px;width:451px;flex-grow:11;flex-shrink:0}.table.table-fixed-header .weight-12{min-width:492px;width:492px;flex-grow:12;flex-shrink:0}.table.table-fixed-header .weight-13{min-width:533px;width:533px;flex-grow:13;flex-shrink:0}.table.table-fixed-header .weight-14{min-width:574px;width:574px;flex-grow:14;flex-shrink:0}.table.table-fixed-header .weight-15{min-width:615px;width:615px;flex-grow:15;flex-shrink:0}.table.table-fixed-header .weight-16{min-width:656px;width:656px;flex-grow:16;flex-shrink:0}.table.table-fixed-header thead tr::after{content:'';display:block;overflow-y:scroll;visibility:hidden}.table.table-fixed-header.table-bordered{border:0}.table.table-fixed-header.table-bordered tbody,.table.table-fixed-header.table-bordered tfoot,.table.table-fixed-header.table-bordered thead{border-left:solid 1px #c5c5c5;border-right:solid 1px #c5c5c5}.table.table-fixed-header.table-bordered thead{border-top:solid 1px #c5c5c5;border-top-left-radius:4px;border-top-right-radius:4px}.table.table-fixed-header.table-bordered tbody,.table.table-fixed-header.table-bordered tfoot{border-bottom:solid 1px #c5c5c5;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.table.table-fixed-header.table-bordered tfoot+tbody{border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.table thead tr.multiline th[colspan] .column-headings{margin-left:-20px;margin-right:-20px}.table thead tr.multiline th[colspan] .column-heading{float:left;padding:0 5px}.table thead tr.multiline th[colspan="2"] .column-heading{width:50%}.table thead tr.multiline th[colspan="3"] .column-heading{width:33.33%}.table thead tr.multiline th[colspan="4"] .column-heading{width:25%}.table thead tr.multiline th[colspan="5"] .column-heading{width:20%}.table thead tr.multiline .column-headings{height:30px;overflow:hidden}.table thead tr.multiline .column-title{color:#8d8d8d;font-size:12px}.table thead tr.multiline .column-subtitle{position:relative;top:-4px;color:#8d8d8d;font-size:10px}.table thead tr.multiline .column-headings input[type=search]{position:relative;top:3px;height:22px;color:#8d8d8d}.table-fixed-header-container{position:relative;overflow-y:hidden}label.required::after{position:absolute;content:"*";color:#fb5000;right:-7px}select{cursor:pointer}select.custom-select.no-caret{background-image:none}select.custom-select{background-position:right}.btn-group select{border:none;height:28px}.form-check-inline{height:30px;line-height:30px}.btn{min-width:105px;min-height:30px}.btn.with-action-icon{padding:0;height:30px;min-width:30px;width:30px;position:relative}.btn.with-action-icon .pstg-action-icon{height:16px;position:absolute;top:6px;left:6px}.btn.with-action-icon.btn-primary .pstg-action-icon{fill:#fff}.btn.with-action-icon.btn-secondary .pstg-action-icon{fill:#454545}.btn.btn-secondary{transition-property:border,box-shadow,color}.btn.btn-secondary.focus,.btn.btn-secondary:focus,.btn.btn-secondary:hover{background-color:#fff}.btn.btn-secondary.focus:not([disabled]),.btn.btn-secondary:focus:not([disabled]),.btn.btn-secondary:hover:not([disabled]){box-shadow:0 1px 2px rgba(0,0,0,.2)}.btn.with-caret{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMiAyOCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1heFlNaWQiPjxwb2x5Z29uIHBvaW50cz0iMC4xLDEyLjIgNC41LDE2LjcgOSwxMi4yIi8+PC9zdmc+) right 0 center no-repeat #fff;padding-right:30px}.btn.with-caret.up{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMiAyOCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1heFlNaWQiPjxwb2x5Z29uIHBvaW50cz0iOSwxNi43IDQuNiwxMi4yIDAuMSwxNi43Ii8+PC9zdmc+)}input.form-control{height:30px;padding-top:0;padding-bottom:0}.input-with-icon{position:relative}.input-with-icon .pstg-action-icon{width:14px;height:14px;position:absolute;z-index:4;top:calc((30px - 14px)/ 2);fill:#c5c5c5}.input-with-icon.after-sm .icon-after .pstg-action-icon,.input-with-icon.before-sm .icon-before .pstg-action-icon{width:10px;height:10px}.input-with-icon.before input{padding-left:calc(9px + 14px + 9px)}.input-with-icon.before-sm input{padding-left:calc(9px + 10px + 9px)}.input-with-icon .icon-before .pstg-action-icon{left:9px}.input-with-icon.after input{padding-right:calc(9px + 14px + 9px)}.input-with-icon.after-sm input{padding-right:calc(9px + 10px + 9px)}.input-with-icon .icon-after .pstg-action-icon{right:9px}.input-with-icon .actionable .pstg-action-icon{transition:fill ease-in-out .15s}.input-with-icon .actionable .pstg-action-icon:active,.input-with-icon .actionable .pstg-action-icon:hover{fill:#454545;cursor:pointer}.custom-select{width:100%;height:30px}.modal .modal-footer.btn-toolbar{margin:0} +/*# sourceMappingURL=bootstrap.css.map */ diff --git a/gui/src/assets/styles/bootstrap.css.map b/gui/src/assets/styles/bootstrap.css.map new file mode 100644 index 00000000..fb80b123 --- /dev/null +++ b/gui/src/assets/styles/bootstrap.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../node_modules/bootstrap/scss/_normalize.scss","../../node_modules/bootstrap/scss/_reboot.scss","../../node_modules/bootstrap/scss/_custom-forms.scss","../../node_modules/bootstrap/scss/_type.scss","../../node_modules/bootstrap/scss/_code.scss","../../node_modules/bootstrap/scss/_button-group.scss","../../node_modules/bootstrap/scss/_dropdown.scss","../../node_modules/bootstrap/scss/_tables.scss","_fontface_proxima_nova.scss","bootstrap.css","_custom.scss","../../node_modules/bootstrap/scss/_print.scss","../../dist/styles/_pstg_variables.scss","../../node_modules/bootstrap/scss/mixins/_tab-focus.scss","../../node_modules/bootstrap/scss/_forms.scss","../../node_modules/bootstrap/scss/_buttons.scss","../../node_modules/bootstrap/scss/_input-group.scss","../../node_modules/bootstrap/scss/_tags.scss","../../node_modules/bootstrap/scss/_images.scss","../../node_modules/bootstrap/scss/mixins/_image.scss","../../node_modules/bootstrap/scss/mixins/_grid-framework.scss","../../node_modules/bootstrap/scss/mixins/_lists.scss","../../node_modules/bootstrap/scss/_grid.scss","../../node_modules/bootstrap/scss/mixins/_grid.scss","../../node_modules/bootstrap/scss/mixins/_clearfix.scss","../../node_modules/bootstrap/scss/mixins/_border-radius.scss","../../node_modules/bootstrap/scss/mixins/_breakpoints.scss","../../node_modules/bootstrap/scss/mixins/_table-row.scss","../../node_modules/bootstrap/scss/_animation.scss","../../node_modules/bootstrap/scss/_responsive-embed.scss","../../node_modules/bootstrap/scss/_modal.scss","../../node_modules/bootstrap/scss/_navbar.scss","../../node_modules/bootstrap/scss/_mixins.scss","../../node_modules/bootstrap/scss/mixins/_forms.scss","../../node_modules/bootstrap/scss/mixins/_buttons.scss","../../node_modules/bootstrap/scss/mixins/_nav-divider.scss","../../node_modules/bootstrap/scss/mixins/_reset-filter.scss","../../node_modules/bootstrap/scss/_alert.scss","../../node_modules/bootstrap/scss/_close.scss","../../node_modules/bootstrap/scss/_nav.scss","../../node_modules/bootstrap/scss/_card.scss","../../node_modules/bootstrap/scss/mixins/_cards.scss","../../node_modules/bootstrap/scss/_breadcrumb.scss","../../node_modules/bootstrap/scss/_pagination.scss","../../node_modules/bootstrap/scss/mixins/_pagination.scss","../../node_modules/bootstrap/scss/mixins/_tag.scss","../../node_modules/bootstrap/scss/_jumbotron.scss","../../node_modules/bootstrap/scss/_progress.scss","../../node_modules/bootstrap/scss/mixins/_alert.scss","../../node_modules/bootstrap/scss/mixins/_gradients.scss","../../node_modules/bootstrap/scss/mixins/_progress.scss","../../node_modules/bootstrap/scss/_media.scss","../../node_modules/bootstrap/scss/_list-group.scss","_bootstrap_override.scss","../../node_modules/bootstrap/scss/mixins/_list-group.scss","../../node_modules/bootstrap/scss/_popover.scss","../../node_modules/bootstrap/scss/_tooltip.scss","../../node_modules/bootstrap/scss/mixins/_reset-text.scss","../../node_modules/bootstrap/scss/_carousel.scss","../../node_modules/bootstrap/scss/utilities/_text.scss","../../node_modules/bootstrap/scss/utilities/_borders.scss","../../node_modules/bootstrap/scss/mixins/_text-hide.scss","../../node_modules/bootstrap/scss/utilities/_align.scss","../../node_modules/bootstrap/scss/utilities/_background.scss","../../node_modules/bootstrap/scss/mixins/_background-variant.scss","../../node_modules/bootstrap/scss/utilities/_clearfix.scss","../../node_modules/bootstrap/scss/utilities/_display.scss","../../node_modules/bootstrap/scss/utilities/_visibility.scss","../../node_modules/bootstrap/scss/utilities/_flex.scss","../../node_modules/bootstrap/scss/utilities/_float.scss","../../node_modules/bootstrap/scss/mixins/_float.scss","../../node_modules/bootstrap/scss/utilities/_screenreaders.scss","../../node_modules/bootstrap/scss/mixins/_screen-reader.scss","../../node_modules/bootstrap/scss/utilities/_spacing.scss","../../node_modules/bootstrap/scss/mixins/_text-truncate.scss","../../node_modules/bootstrap/scss/mixins/_text-emphasis.scss"],"names":[],"mappings":";;;;;AAuEA,SA6GA,IACA,IAIE,eAAgB,SChElB,QAQA,GAFA,GAnBA,EAoBA,GANE,cAAe,KA2JjB,QAQA,GAEE,WAAY,KA1Qd,KAiVA,ODTE,WAAY,WErNd,eDwOA,mBAKE,mBAAoB,KD7FtB,OGxOA,GHyOA,MAlCE,SAAU,QIpNZ,IJsUA,SC7JE,SAAU,KIpIZ,sBAnCA,wBAAA,0BCDA,eCuHA,oBAAA,iBFlFE,MAAO,KGzET,WACE,YAAa,eACb,IAAK,mCAAA,mBACL,YAAa,IACb,WAAY,OAGd,WACE,YAAa,eACb,IAAK,qCAAA,mBACL,YAAa,IACb,WAAY,OAGd,WACE,YAAa,eACb,IAAK,8BAAA,mBACL,YAAa,IACb,WAAY,OAGd,WACE,YAAa,eACb,IAAK,gCAAA,mBACL,YAAa,IACb,WAAY,OAGd,WACE,YAAa,eACb,IAAK,sCAAA,mBACL,YAAa,IACb,WAAY,OAGd,WACE,YAAa,eACb,IAAK,wCAAA,mBACL,YAAa,IACb,WAAY,OAId,WACE,YAAa,eACb,IAAK,kCAAA,mBACL,YAAa,IACb,WAAY,OAGd,WACE,YAAa,eACb,IAAK,oCAAA,mBACL,YAAa,IACb,WAAY,mFR9Cd,KACE,YAAa,WACb,YAAa,KACb,qBAAsB,KACtB,yBAA0B,KAoB5B,QACA,MACA,QACA,WACA,OACA,OACA,OACA,KACA,KACA,IACA,QACA,QACE,QAAS,MAOX,MACA,OACA,SACA,MACE,QAAS,aAOX,sBACE,QAAS,KACT,OAAQ,ES4BV,STZA,SAEE,QAAS,KAWX,EACE,iBAAkB,YAClB,6BAA8B,QAQhC,SACA,QACE,cAAe,EAWjB,YAEE,gBAAiB,UACjB,gBAAiB,UAAA,OAOnB,EACA,OAUE,YAAa,OAOf,IACE,WAAY,OAQd,GAEE,OAAQ,MAAA,ECVV,GA9CA,GAAI,GAAI,GAAI,GAAI,GAAI,GAoMpB,MAGE,cAAe,MDxIjB,KAEE,MAAO,KAOT,MACE,UAAW,IAQb,IACA,IACE,UAAW,IACX,YAAa,EACb,SAAU,SAIZ,IACE,OAAQ,OAGV,IACE,IAAK,MAUP,IACE,aAAc,KCsBd,eAAgB,ODflB,eACE,SAAU,OAWZ,KACA,IACA,IACA,KAEE,UAAW,IA8Bb,OACA,MACA,SACA,OACA,SACE,KAAM,QACN,OAAQ,EAOV,SACE,YAAa,IAkBf,OACA,OACE,eAAgB,KS3GlB,aACA,cTmHA,OACA,mBAGE,mBAAoB,OSnHtB,gCACA,+BACA,gCTwHA,yBAIE,aAAc,KACd,QAAS,ESxHX,6BACA,4BACA,6BT6HA,sBAIE,QAAS,WAAA,OAAA,IAiCX,SCjBE,OAAQ,SQ9HV,gBACA,aTyJE,WAAY,WACZ,QAAS,EStJX,yCACA,yCT8JE,OAAQ,KS3JV,cToKE,mBAAoB,UACpB,eAAgB,KSjKlB,4CACA,yCTyKE,mBAAoB,KAOtB,4BACE,MAAO,QACP,QAAS,IAQX,6BACE,mBAAoB,OACpB,KAAM,QCvRR,GG3HA,QH4HE,YSsDe,IT3EjB,QA8LA,OADA,MAgDA,OA9CA,OACA,SAoDE,YAAa,QUlWb,aA8CE,WAeA,IAhBA,IAeA,GAEE,kBAAmB,MA7DrB,EAEA,QADA,SAEA,eAGA,uBADA,gBAEA,eAHA,cAOE,YAAa,eAEb,WAAY,eAGd,EACA,UACE,gBAAiB,UAQnB,mBACE,QAAS,KAAK,YAAY,IAc5B,IACE,YAAa,mBAGf,WADA,IAEE,ODkBS,IClBa,MAAM,KAS9B,MACE,QAAS,mBASX,GACA,GAFA,EAGE,QAAS,EACT,OAAQ,EAGV,GACA,GACE,iBAAkB,MAMpB,QACE,QAAS,KAEX,YACA,oBAEI,iBAAkB,eAGtB,KACE,ODzBS,ICyBa,MAAM,KAG9B,OACE,gBAAiB,mBADnB,UAAA,UAKI,iBAAkB,eAGtB,mBAAA,mBAGI,OAAQ,IAAA,MAAA,gBVoLhB,MAkFA,OACE,QAAS,aArWX,KAqCE,UW/BoB,KXsCpB,mBAAoB,UAEpB,4BAA6B,YA1C/B,EAEA,QADA,SAEE,WAAY,QAoBZ,cAAgB,MAAO,aAsBzB,KDlDE,OAAQ,ECoDR,YSmEuB,eAAgB,cAAe,mBAAoB,WAAY,OAAQ,iBAAkB,MAAO,WTlEvH,US0Ee,KTzEf,YS8EiB,IT5EjB,MWpEiB,QXsEjB,iBWnEkB,QHkTpB,sBRtOE,QAAS,YA0CX,GA9BA,GAAI,GAAI,GAAI,GAAI,GAAI,GA4BpB,GAnBA,EAoBA,GA5BE,WAAY,EAgBd,0BAFA,YAGE,OAAQ,KACR,cAAe,IAAI,OW5GH,QX+GlB,QAEE,WAAY,OAWd,MAEA,MACA,MAFA,MAGE,cAAe,EAOjB,GAEE,YAAa,EAGf,WA8DA,OA7DE,OAAQ,EAAA,EAAA,KAQV,EACE,MWhKU,QXiKV,gBSrEsB,KTmExB,QAAA,QAKI,MSvEoB,QTwEpB,gBSvEoB,UTiExB,QYzJE,QAAS,yBAAA,KAAA,IACT,eAAgB,KZ4KlB,8BAAA,oCAAA,oCACE,MAAO,QACP,gBAAiB,KAFnB,oCAUI,QAAS,EQ+Mb,cR7JE,OAAQ,QazOV,uBb0TA,8BADA,2BazGM,OJoH2B,YDwEjC,cRrJA,EACA,KACA,OAEA,MACA,MACA,OACA,QACA,SACE,aAAc,aAQhB,MAEE,gBAAiB,SAEjB,iBS7C8B,KTgDhC,QACE,YW3L0B,IADA,KX6L1B,eW5L0B,IADA,KX8L1B,MW9QgB,QXgRhB,aAAc,OAuBhB,aACE,QAAS,OAAA,IACT,QAAS,yBAAA,KAAA,IAuBX,iBACA,iBACA,2BACA,kBAME,mBAAoB,QAQtB,SAIE,UAAW,EAEX,QAAS,EACT,OAAQ,EACR,OAAQ,EAGV,ODRE,MAAO,QAEP,UAAW,KAEX,YAAa,OCMb,QAAS,MACT,MAAO,KACP,QAAS,EACT,cAAe,MACf,UAAW,OctWb,KTsIA,iBA3EA,eUoFA,iBTMA,oBUtJA,KDqJE,YAAa,OP6Tf,SRrFE,QAAS,eE7XX,IAAK,IAAK,IAAK,IAAK,IAAK,IADzB,GAAI,GAAI,GAAI,GAAI,GAAI,GAElB,cOqKwB,MPpKxB,YOqKuB,QPpKvB,YOqKuB,IPpKvB,YOqKuB,IPpKvB,MOqKuB,QPtEzB,YAzDA,GA2DE,cOpDS,KP7BX,WAIA,WAIA,WAIA,WAlBA,MAoBE,YOiIgB,IP5Jd,IAAJ,GAAU,UO6IK,OP5IX,IAAJ,GAAU,UO6IK,KP5IX,IAAJ,GAAU,UO6IK,QP5IX,IAAJ,GAAU,UO6IK,OP5IX,IAAJ,GAAU,UO6IK,QP5IX,IAAJ,GAAU,UO6IK,KP3If,MACE,UO4JiB,QPvJnB,WACE,UOsIc,KPnIhB,WACE,UOmIc,OPhIhB,WACE,UOgIc,OP7HhB,WACE,UO6Hc,OPpHhB,GHqME,WAAY,YACZ,OAAQ,EGrMR,WOMS,KPJT,OAAQ,EACR,WOwBa,IPxBgB,MO2Ib,eQxLlB,qCAAA,mCAAA,WAMA,eCCE,OAAQ,KC0BA,UAAW,KjBqBrB,OADA,MAEE,UOsHgB,IPrHhB,YAAa,IAIf,MADA,KAEE,QO8Ha,KP7Hb,iBOsf+B,QPzejC,aALA,ekBzEE,aAAc,EACd,WAAY,KlBgFd,kBACE,QAAS,aADX,mCAII,aOgHkB,IYpMpB,WAYA,iBCZA,YAAa,KACb,aAAc,KpB6FhB,YACE,UAAW,IACX,eAAgB,UAIlB,YACE,QAAU,MOnDD,KPqDT,UO+EyB,QP9EzB,YOgFwB,OPhFc,MSlGpB,QTqGpB,mBACE,QAAS,MACT,UAAW,IACX,MSzGgB,QTsGlB,2BAMI,QAAS,cAKb,oBACE,cOrES,KPsET,aAAc,EACd,WAAY,MACZ,aO8DwB,OP9De,MSpHrB,QTqHlB,YAAa,EAGf,+CAEI,QAAS,GAFb,8CAKI,QAAS,cEuBb,sCA1HA,oBC/BA,wBkBJI,QAAS,GNWb,eACE,QRouB4B,OQnuB5B,iBNJkB,QMKlB,OR4Da,IQ5DmB,MRquBJ,KejvB1B,cbmBiB,IMLnB,WAAY,IAAA,IAAA,YdTd,KASA,IACE,QMkyB4B,MADA,MNhyB5B,UM+xB4B,Ie/yB1B,cbmBiB,IMMrB,QAEE,QAAS,aAGX,YACE,cAAgB,MAChB,YAAa,EXhCf,OH+BA,IG5BE,cGgDS,KQhBX,gBACE,URotByB,IQntBzB,MN/BgB,QRTlB,KACA,IACA,IACA,KACE,YMwIuB,MAAO,OAAQ,SAAU,kBAAmB,cAAe,UNpIpF,KAGE,MM0yB4B,QNzyB5B,iBM0yB4B,QNryB9B,IAGE,MMoyB4B,KNnyB5B,iBMoyB4B,KNxyB9B,QASI,QAAS,EACT,UAAW,KWtBf,KAoGA,UTzCA,eUqBE,YAAa,IZnDf,IACE,QAAS,MACT,WAAY,EAEZ,UM4wB4B,IN3wB5B,MQhCiB,QR2BnB,SASI,QAAS,EACT,UAAW,QACX,MAAO,QACP,iBAAkB,YAClB,cAAe,EkB3CjB,WAYA,iBCYI,cAAgB,KAChB,aAAgB,KnBuBtB,gBACE,WMywB4B,MNxwB5B,WAAY,OkB5BZ,KCUE,QAAS,KACT,UAAW,KAQT,aAAe,MACf,YAAe,MGFjB,yBJxCF,WCcI,MbgGM,Ma/FN,UAAW,KDOf,KCmBI,aAAe,MACf,YAAe,MHxCnB,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UGsBI,cAAgB,KAChB,aAAgB,MGelB,yBJxCF,WCcI,MbiGM,MahGN,UAAW,KDOf,KCmBI,aAAe,MACf,YAAe,MHxCnB,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UGsBI,cAAgB,KAChB,aAAgB,MGelB,yBJxCF,WCcI,MbkGM,MajGN,UAAW,KDOf,KCmBI,aAAe,MACf,YAAe,MHxCnB,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UGsBI,cAAgB,KAChB,aAAgB,MGelB,0BJxCF,WCcI,MbmGM,OalGN,UAAW,KDOf,KCmBI,aAAe,MACf,YAAe,MHxCnB,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UGsBI,cAAgB,KAChB,aAAgB,MHvBpB,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,QAAA,UAAA,WAAA,WAAA,WAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UAAA,UACE,SAAU,SAEV,WAAY,IAGV,MAAO,KGgBP,cAAgB,KAChB,aAAgB,KHOd,QACE,WAAY,EACZ,UAAW,EACX,UAAW,KAKb,UG6BJ,KAAM,EAAE,EAAE,SAIV,UAAW,SHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,KAIV,UAAW,KH1BL,WG0CR,MAAmD,KH1C3C,WG0CR,MAAqB,SH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,KH1Cb,WGsCR,KAAkD,KHtC1C,WGsCR,KAAoB,SHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,KH7BZ,aGyBR,YAAa,SHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,cGyBR,YAAa,UHzBL,cGyBR,YAAa,UGzCX,yBNRI,QACE,WAAY,EACZ,UAAW,EACX,UAAW,KAKb,UG6BJ,KAAM,EAAE,EAAE,SAIV,UAAW,SHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,KAIV,UAAW,KH1BL,WG0CR,MAAmD,KH1C3C,WG0CR,MAAqB,SH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,KH1Cb,WGsCR,KAAkD,KHtC1C,WGsCR,KAAoB,SHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,KH7BZ,aGyBR,YAAa,EHzBL,aGyBR,YAAa,SHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,cGyBR,YAAa,UHzBL,cGyBR,YAAa,WGzCX,yBNRI,QACE,WAAY,EACZ,UAAW,EACX,UAAW,KAKb,UG6BJ,KAAM,EAAE,EAAE,SAIV,UAAW,SHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,KAIV,UAAW,KH1BL,WG0CR,MAAmD,KH1C3C,WG0CR,MAAqB,SH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,KH1Cb,WGsCR,KAAkD,KHtC1C,WGsCR,KAAoB,SHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,KH7BZ,aGyBR,YAAa,EHzBL,aGyBR,YAAa,SHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,cGyBR,YAAa,UHzBL,cGyBR,YAAa,WGzCX,yBNRI,QACE,WAAY,EACZ,UAAW,EACX,UAAW,KAKb,UG6BJ,KAAM,EAAE,EAAE,SAIV,UAAW,SHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,KAIV,UAAW,KH1BL,WG0CR,MAAmD,KH1C3C,WG0CR,MAAqB,SH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,KH1Cb,WGsCR,KAAkD,KHtC1C,WGsCR,KAAoB,SHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,KH7BZ,aGyBR,YAAa,EHzBL,aGyBR,YAAa,SHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,cGyBR,YAAa,UHzBL,cGyBR,YAAa,WGzCX,0BNRI,QACE,WAAY,EACZ,UAAW,EACX,UAAW,KAKb,UG6BJ,KAAM,EAAE,EAAE,SAIV,UAAW,SHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,UG6BJ,KAAM,EAAE,EAAE,IAIV,UAAW,IHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,UAIV,UAAW,UHjCP,WG6BJ,KAAM,EAAE,EAAE,KAIV,UAAW,KH1BL,WG0CR,MAAmD,KH1C3C,WG0CR,MAAqB,SH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,UH1Cb,WG0CR,MAAqB,IH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,UH1Cb,YG0CR,MAAqB,KH1Cb,WGsCR,KAAkD,KHtC1C,WGsCR,KAAoB,SHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,UHtCZ,WGsCR,KAAoB,IHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,UHtCZ,YGsCR,KAAoB,KH7BZ,aGyBR,YAAa,EHzBL,aGyBR,YAAa,SHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,UHzBL,aGyBR,YAAa,IHzBL,cGyBR,YAAa,UHzBL,cGyBR,YAAa,WhBlFf,OACE,MAAO,KACP,UAAW,KAFb,UAAA,UAOI,QKgFwB,IADA,KL9ExB,eAAgB,IAChB,WKWgB,ILXgB,MKHlB,QLNlB,gBAaI,eAAgB,OAChB,cAAgB,IAAyB,MKR3B,QLNlB,mBAkBI,WAAa,IAAyB,MKZxB,QLNlB,cAsBI,iBKfgB,QLwBpB,aAAA,aAGI,QG6L4B,MHpLhC,gBAAA,mBAAA,mBACE,OKxBkB,ILwBU,MKtCZ,QLqClB,yBAAA,yBAWM,oBAAsB,IAU5B,yCAEI,iBGgK4B,gBHvJhC,4BAGM,iBKMkC,QenFtC,cAAA,iBAAA,iBAII,iBfgFmC,Qe1EvC,iCAAA,oCAAA,oCAKM,iBAJe,QAXrB,eAAA,kBAAA,kBAII,iBjByiB2B,QiBniB/B,kCAAA,qCAAA,qCAKM,iBAJe,QAXrB,YAAA,eAAA,eAII,iBjB6iB2B,QiBviB/B,+BAAA,kCAAA,kCAKM,iBAJe,QAXrB,eAAA,kBAAA,kBAII,iBjBijB2B,QiB3iB/B,kCAAA,qCAAA,qCAKM,iBAJe,QAXrB,cAAA,iBAAA,iBAII,iBjBsjB2B,QiBhjB/B,iCAAA,oCAAA,oCAKM,iBAJe,QpByFvB,kBAEI,MAAO,KACP,iBKpGe,QLwGnB,kBAEI,MKzGa,QL0Gb,iBKxGgB,QL4GpB,eACE,MK7GkB,QL8GlB,iBKjHiB,QL+GnB,kBAAA,kBAAA,wBAOI,aKrHa,QL8GjB,8BAWI,OAAQ,EAYZ,kBACE,QAAS,MACT,MAAO,KACP,WAAY,EACZ,WAAY,KqBtHd,YC1BA,kBCUA,OALA,YC4EA,gBD/DE,SAAU,OvBuIZ,oBAMI,QAAS,MANb,iBAAA,iBAYI,WK/IgB,IL+IgB,MK7JlB,QL8Jd,YKhJgB,ILgJiB,MK9JnB,QLiJlB,4BAAA,4BAgBM,aKnJc,ILmJoB,MKjKtB,QLiJlB,gDAAA,gDAAA,gDAAA,gDAAA,gDAAA,gDA0BQ,cK7JY,IL6JuB,MK3KzB,QLiJlB,oBAAA,oBAoCM,QAAS,gBACT,OKxKc,ILwKc,MKtLhB,QE+LlB,YAnMA,cA8EA,mBACA,oBA0GA,WAYE,QAAS,MArMX,cAEE,MAAO,KAGP,QF0B4B,IADA,KExB5B,UJuIe,KItIf,YJyR+B,KIxR/B,MFNiB,QEOjB,iBJyR+B,KIvR/B,iBAAkB,KAClB,gBAAiB,YACjB,OJyDa,IIzDmB,MFMd,QEDhB,cFgBqB,IoB5BrB,WlBmBkB,aAAa,YAAY,KAAM,WAAW,YAAY,KAzB5E,0BA6BI,iBAAkB,YAClB,OAAQ,EA9BZ,oBmB0CI,MrBxCe,QqByCf,iBvBuP6B,KuBtP7B,avBmQ6B,QuBlQ7B,QAAS,EnB7Cb,2BAsCI,MFnCa,QEqCb,QAAS,EAxCb,uBAAA,wBAkDI,iBF7CgB,QE+ChB,QAAS,EAQb,gDAGI,OAAQ,iBAHZ,qCAYI,MFtEe,QEuEf,iBJyN6B,KIxMjC,gBACE,YF5D4B,IE6D5B,eF7D4B,IE8D5B,cAAe,EAGjB,mBACE,YJwN+B,OIvN/B,eJuN+B,OItN/B,UJ2Ce,QIxCjB,mBACE,YJ+M+B,OI9M/B,eJ8M+B,OI7M/B,UJsCe,QI5BjB,iBACE,YFrF4B,IEsF5B,eFtF4B,IEuF5B,cAAe,EACf,UJsBe,KIbjB,qBACE,YFlG4B,IEmG5B,eFnG4B,IEoG5B,YJ6J+B,KI5J/B,OAAQ,MAAA,YACR,aAAc,IAAA,EALhB,qCAAA,qCAAA,kDAAA,uDAAA,0DAAA,kDAAA,uDAAA,0DASI,cAAe,EACf,aAAc,EAalB,iBAAA,8BAAA,mCAAA,sCACE,QJ8J+B,OADA,MI5J/B,UJVe,QejJb,cbmBiB,IE4IrB,wEAAA,gEAAA,qEAAA,mDAEI,OJ8J+B,UI1JnC,iBAAA,8BAAA,mCAAA,sCACE,QJqJ+B,OADA,OInJ/B,UJvBe,QehJb,cbmBiB,IEwJrB,wEAAA,gEAAA,qEAAA,mDAEI,OJiJ+B,WIvInC,YACE,cJyI+B,IItIjC,WAEE,WAAa,OAQf,YACE,SAAU,SAEV,cAAgB,OAHlB,wBAOI,WAAY,QAiBhB,kBAkCA,uBACE,WAAa,OA3Df,uCAYM,MF3MY,QE4MZ,OJoH2B,YI9FjC,mBAjBA,kBAoBE,aAAc,QACd,cAAe,EAEf,OAAQ,QAjBV,kBACE,SAAU,SAEV,YAAa,SAHf,6BAMI,SAAU,Oc3Md,YtB1BA,UADA,QAEE,SAAU,SQyOZ,mBACE,SAAU,SACV,QAAS,aAGT,eAAgB,OALlB,sCASI,YAAa,OATjB,4BAaI,MF/Oc,QEgPd,OJgF6B,YIjEjC,qBAFA,sBACA,sBAEE,cAAgB,KAChB,kBAAmB,UACnB,oBAAqB,OAAO,MAAO,MACnC,gBAAkB,KAAoB,KmBlQtC,6BADA,gCADA,+BAFA,oCACA,iCAIE,MrBVS,QqBcX,2BACE,arBfS,QqBcX,iCAKM,WvByRyB,KuBzRM,EAAE,EAAE,IAAI,QAM7C,gCACE,MrB1BS,QqB2BT,arB3BS,QqB4BT,iBAAkB,QnBmPtB,mCAII,iBJ0IgB,sPuBpZlB,6BADA,gCADA,+BAFA,oCACA,iCAIE,MrBRU,QqBYZ,2BACE,arBbU,QqBYZ,iCAKM,WvByRyB,KuBzRM,EAAE,EAAE,IAAI,QAM7C,gCACE,MrBxBU,QqByBV,arBzBU,QqB0BV,iBAAkB,KnB2PtB,mCAII,iBJqIgB,+TuBvZlB,4BADA,+BADA,8BAFA,mCACA,gCAIE,MrBPO,QqBWT,0BACE,arBZO,QqBWT,gCAKM,WvByRyB,KuBzRM,EAAE,EAAE,IAAI,QAM7C,+BACE,MrBvBO,QqBwBP,arBxBO,QqByBP,iBAAkB,QnBmQtB,iCAII,iBJgIe,gSgBxXf,yBZsQJ,kCAAA,yBAoBM,QAAS,aApBf,yBAAA,iCAAA,yBAkDM,cAAe,EACf,eAAgB,OAnDtB,2BAaM,QAAS,aACT,MAAO,KACP,eAAgB,OAftB,0BAwBM,QAAS,aACT,MAAO,KACP,eAAgB,OA1BtB,wCAAA,6CAAA,2CA+BQ,MAAO,KA/Bf,wCAqCM,MAAO,KArCb,yBAgDM,QAAS,aACT,WAAY,EAjDlB,+BAsDM,aAAc,EAtDpB,+BAyDM,SAAU,SACV,YAAa,EA1DnB,kDA+DM,IAAK,GCpNX,WAaA,6BADA,4BADA,6BAII,MAAO,KAvKX,KACE,QAAS,aAET,YL2O+B,KK1O/B,WAAY,OAEZ,eAAgB,OAChB,OAAQ,QACR,YAAa,KACb,OL6Da,IK7DmB,MAAM,YmB8FtC,QtBnEmB,MADA,KsBqEnB,UxBqCe,Ke/Ib,cboCqB,IoB5BrB,WjBKkB,IAAI,IAAI,YAX9B,kBAAA,kBAAA,WAAA,kBAAA,kBAAA,WFAE,QAAS,yBAAA,KAAA,IACT,eAAgB,KEDlB,WAAA,WAAA,WAuBI,gBAAiB,KAvBrB,YAAA,YA+BI,iBAAkB,KAClB,QAAS,EAhCb,cAAA,cAsCI,OL8R6B,YK7R7B,QAAS,IAMb,eACA,yBACE,eAAgB,KAQlB,amBpDE,MtBmCuB,KsBlCvB,iBtBmCkC,QsBlClC,atBmC8B,QGehC,mBAAA,mBAAA,mBmB9CI,MtB6BqB,KsB5BrB,iBAVkB,QAWd,aAVU,QnBsDlB,oBAAA,oBmBhCE,mCACE,MtBcqB,KsBbrB,iBAzBkB,QA0Bd,aAzBU,QA2Bd,iBAAkB,KnB2BtB,0BAAA,0BAAA,0BAAA,0BAAA,0BAAA,0BmBhCE,yCAAA,yCAAA,yCAWI,MtBImB,KsBHnB,iBAAkB,QACd,aAAc,QnBmBxB,4BAAA,4BAAA,4BAAA,4BAAA,4BAAA,4BmBXM,iBtBL8B,QsBM1B,atBLsB,QGkBhC,emBvDE,MtBsCyB,QsBrCzB,iBtBsCoC,KsBrCpC,atBsCgC,QGelC,qBAAA,qBAAA,qBmBjDI,MtBgCuB,QsB/BvB,iBAVkB,QAWd,aAVU,QnByDlB,sBAAA,sBmBnCE,qCACE,MtBiBuB,QsBhBvB,iBAzBkB,QA0Bd,aAzBU,QA2Bd,iBAAkB,KnB8BtB,4BAAA,4BAAA,4BAAA,4BAAA,4BAAA,4BmBnCE,2CAAA,2CAAA,2CAWI,MtBOqB,QsBNrB,iBAAkB,QACd,aAAc,QnBsBxB,8BAAA,8BAAA,8BAAA,8BAAA,8BAAA,8BmBdM,iBtBFgC,KsBG5B,atBFwB,QGkBlC,UmB1DE,MtByCoB,KsBxCpB,iBtByC+B,QsBxC/B,atByC2B,KGe7B,gBAAA,gBAAA,gBmBpDI,MtBmCkB,KsBlClB,iBAVkB,QAWd,aAVU,QnB4DlB,iBAAA,iBmBtCE,gCACE,MtBoBkB,KsBnBlB,iBAzBkB,QA0Bd,aAzBU,QA2Bd,iBAAkB,KnBiCtB,uBAAA,uBAAA,uBAAA,uBAAA,uBAAA,uBmBtCE,sCAAA,sCAAA,sCAWI,MtBUgB,KsBThB,iBAAkB,QACd,aAAc,QnByBxB,yBAAA,yBAAA,yBAAA,yBAAA,yBAAA,yBmBjBM,iBtBC2B,QsBAvB,atBCmB,KGkB7B,amB7DE,MtB4CuB,KsB3CvB,iBtB4CkC,QsB3ClC,atB4C8B,QGehC,mBAAA,mBAAA,mBmBvDI,MtBsCqB,KsBrCrB,iBAVkB,QAWd,aAVU,QnB+DlB,oBAAA,oBmBzCE,mCACE,MtBuBqB,KsBtBrB,iBAzBkB,QA0Bd,aAzBU,QA2Bd,iBAAkB,KnBoCtB,0BAAA,0BAAA,0BAAA,0BAAA,0BAAA,0BmBzCE,yCAAA,yCAAA,yCAWI,MtBamB,KsBZnB,iBAAkB,QACd,aAAc,QnB4BxB,4BAAA,4BAAA,4BAAA,4BAAA,4BAAA,4BmBpBM,iBtBI8B,QsBH1B,atBIsB,QGkBhC,amBhEE,MxBgQ+B,KwB/P/B,iBtBNY,QsBOZ,atBPY,QGqEd,mBAAA,mBAAA,mBmB1DI,MxB0P6B,KwBzP7B,iBAVkB,QAWd,aAVU,QnBkElB,oBAAA,oBmB5CE,mCACE,MxB2O6B,KwB1O7B,iBAzBkB,QA0Bd,aAzBU,QA2Bd,iBAAkB,KnBuCtB,0BAAA,0BAAA,0BAAA,0BAAA,0BAAA,0BmB5CE,yCAAA,yCAAA,yCAWI,MxBiO2B,KwBhO3B,iBAAkB,QACd,aAAc,QnB+BxB,4BAAA,4BAAA,4BAAA,4BAAA,4BAAA,4BmBvBM,iBtB9CQ,QsB+CJ,atB/CI,QGwEd,YmBnEE,MtB+CsB,KsB9CtB,iBtB+CiC,QsB9CjC,atB+C6B,QGkB/B,kBAAA,kBAAA,kBmB7DI,MtByCoB,KsBxCpB,iBAVkB,QAWd,aAVU,QnBqElB,mBAAA,mBmB/CE,kCACE,MtB0BoB,KsBzBpB,iBAzBkB,QA0Bd,aAzBU,QA2Bd,iBAAkB,KnB0CtB,yBAAA,yBAAA,yBAAA,yBAAA,yBAAA,yBmB/CE,wCAAA,wCAAA,wCAWI,MtBgBkB,KsBflB,iBAAkB,QACd,aAAc,QnBkCxB,2BAAA,2BAAA,2BAAA,2BAAA,2BAAA,2BmB1BM,iBtBO6B,QsBNzB,atBOqB,QGuB/B,qBmBpBE,MtBhBkC,QsBiBlC,iBAAkB,KAClB,iBAAkB,YAClB,atBnBkC,QGoCpC,4BAAA,2BAAA,4BAAA,2BAAA,2BmBAE,2CAdE,MAAO,KACP,iBtBvBgC,QsBwB5B,atBxB4B,QGoCpC,kCAAA,kCAAA,kCAAA,kCAAA,kCAAA,kCmBAE,iDAAA,iDAAA,iDAQI,MAAO,KACP,iBAAkB,QACd,aAAc,QnBVxB,oCAAA,oCAAA,oCAAA,oCAAA,oCAAA,oCmBkBM,aAAc,QnBfpB,uBmBvBE,MtBZgC,QsBahC,iBAAkB,KAClB,iBAAkB,YAClB,atBfgC,QGmClC,8BAAA,6BAAA,8BAAA,6BAAA,6BmBHE,6CAdE,MAAO,KACP,iBtBnB8B,QsBoB1B,atBpB0B,QGmClC,oCAAA,oCAAA,oCAAA,oCAAA,oCAAA,oCmBHE,mDAAA,mDAAA,mDAQI,MAAO,KACP,iBAAkB,QACd,aAAc,QnBPxB,sCAAA,sCAAA,sCAAA,sCAAA,sCAAA,sCmBeM,aAAc,QnBZpB,kBmB1BE,MtBV+B,QsBW/B,iBAAkB,KAClB,iBAAkB,YAClB,atBb+B,QGoCjC,yBAAA,wBAAA,yBAAA,wBAAA,wBmBNE,wCAdE,MAAO,KACP,iBtBjB6B,QsBkBzB,atBlByB,QGoCjC,+BAAA,+BAAA,+BAAA,+BAAA,+BAAA,+BmBNE,8CAAA,8CAAA,8CAQI,MAAO,KACP,iBAAkB,QACd,aAAc,QnBJxB,iCAAA,iCAAA,iCAAA,iCAAA,iCAAA,iCmBYM,aAAc,OnBTpB,qBmB7BE,MtBPkC,QsBQlC,iBAAkB,KAClB,iBAAkB,YAClB,atBVkC,QGoCpC,4BAAA,2BAAA,4BAAA,2BAAA,2BmBTE,2CAdE,MAAO,KACP,iBtBdgC,QsBe5B,atBf4B,QGoCpC,kCAAA,kCAAA,kCAAA,kCAAA,kCAAA,kCmBTE,iDAAA,iDAAA,iDAQI,MAAO,KACP,iBAAkB,QACd,aAAc,QnBDxB,oCAAA,oCAAA,oCAAA,oCAAA,oCAAA,oCmBSM,aAAc,QnBNpB,qBmBhCE,MtBzDY,QsB0DZ,iBAAkB,KAClB,iBAAkB,YAClB,atB5DY,QGyFd,4BAAA,2BAAA,4BAAA,2BAAA,2BmBZE,2CAdE,MAAO,KACP,iBtBhEU,QsBiEN,atBjEM,QGyFd,kCAAA,kCAAA,kCAAA,kCAAA,kCAAA,kCmBZE,iDAAA,iDAAA,iDAQI,MAAO,KACP,iBAAkB,QACd,aAAc,QnBExB,oCAAA,oCAAA,oCAAA,oCAAA,oCAAA,oCmBMM,aAAc,QnBHpB,oBmBnCE,MtBJiC,QsBKjC,iBAAkB,KAClB,iBAAkB,YAClB,atBPiC,QGuCnC,2BAAA,0BAAA,2BAAA,0BAAA,0BmBfE,0CAdE,MAAO,KACP,iBtBX+B,QsBY3B,atBZ2B,QGuCnC,iCAAA,iCAAA,iCAAA,iCAAA,iCAAA,iCmBfE,gDAAA,gDAAA,gDAQI,MAAO,KACP,iBAAkB,QACd,aAAc,QnBKxB,mCAAA,mCAAA,mCAAA,mCAAA,mCAAA,mCmBGM,aAAc,QnBOpB,UAEE,MH5GU,QG6GV,cAAe,EAHjB,UAAA,iBAAA,iBAAA,mBASI,iBAAkB,YATtB,UAAA,iBAAA,gBAAA,gBAeI,aAAc,YAflB,gBAAA,gBAqBI,MLlCoB,QKmCpB,gBLlCoB,UKmCpB,iBAAkB,YAvBtB,yBAAA,yBA2BM,MH3HY,QG4HZ,gBAAiB,KAUvB,mBAAA,QmBnCE,QxB0K+B,OADA,OwBxK/B,UxBsCe,QehJb,cbmBiB,IG6HrB,mBAAA,QmBvCE,QxBuK+B,OADA,MwBrK/B,UxBuCe,QejJb,cbmBiB,IGuIrB,WACE,QAAS,MAKX,sBACE,WLoH+B,MkBzRjC,MACE,QAAS,EACT,WAAY,QAAA,KAAA,OAFd,SAKI,QAAS,EAIb,UACE,QAAS,KADX,aAGI,QAAS,MAIb,eAEI,QAAS,UAIb,kBAEI,QAAS,gBAIb,YAEE,OAAQ,EAER,2BAA4B,KAC5B,oBAAqB,KACrB,oBAAqB,OtB5BvB,wBAGI,QAAS,aACT,MAAO,EACP,OAAQ,EACR,YI8MqB,KJ7MrB,eAAgB,OAEhB,WI2MqB,KJ3MI,MACzB,aI0MqB,KJ1MM,MAAM,YACjC,YIyMqB,KJzMK,MAAM,YAXpC,uBAgBI,QAAS,EAIb,gCAGM,WAAY,EACZ,cI4LmB,KJ5LS,MAMlC,eACE,SAAU,SACV,IAAK,KACL,KAAM,EACN,QIkayB,KJjazB,QAAS,KAET,UIiY+B,MJhY/B,QIiY+B,MJjYF,EAC7B,OIiY+B,QJjYF,EAAE,EAC/B,UIqGe,KJpGf,MMvCiB,QNwCjB,WAAY,KACZ,WAAY,KACZ,iBI6X+B,KJ5X/B,gBAAiB,YACjB,OIwBa,IJxBkB,MI4XA,gBe5a7B,cbmBiB,INmCrB,kB6BrDE,OAAQ,IACR,OAAS,MAAe,EACxB,SAAU,OACV,iBzB0a+B,QJjXjC,eACE,QAAS,MACT,MAAO,KACP,QAAS,II0XsB,OJzX/B,MAAO,KAEP,MM/DiB,QNgEjB,WAAY,QAEZ,eACA,OAAQ,ED2HV,uEAXA,4DAhHA,8DAtBA,yEWZA,8DAFA,sDACA,oDSpCI,cT2CuB,EVkB3B,qBAAA,qBAaI,MIwW6B,QJvW7B,gBAAiB,KACjB,iBIuW6B,QJtXjC,sBAAA,4BAAA,4BAqBM,MM9Ea,QN+Eb,gBAAiB,KACjB,iBM7Ec,QN8Ed,QAAS,EAxBf,wBAAA,8BAAA,8BAiCM,MMxFY,QNuDlB,8BAAA,8BAsCM,gBAAiB,KACjB,OIkO2B,YJjO3B,iBAAkB,YAClB,iBAAkB,K8BpGtB,OAAQ,8D9B2GV,qBAGI,QAAS,MAHb,QAQI,QAAS,EAQb,qBACE,MAAO,EACP,KAAM,KAGR,oBACE,MAAO,KACP,KAAM,EAIR,iBACE,QAAS,MACT,QI+R+B,MAiBA,OJ/S/B,cAAe,EACf,UIKe,QJJf,MMvIgB,QN4IlB,mBACE,SAAU,MACV,IAAK,EACL,MAAO,EACP,OAAQ,EACR,KAAM,EACN,QI4S0B,IJpS5B,eACA,sCAGI,QAAS,GACT,WAAY,EACZ,cIgDqB,KJhDO,MANhC,uBACA,8CAUI,IAAK,KACL,OAAQ,KACR,cI6P6B,QL3ajC,WACA,oBACE,SAAU,SACV,QAAS,aACT,eAAgB,OAHlB,yBADA,gBAOI,SAAU,SACV,MAAO,KACP,cAAe,EARnB,gCAAA,gCAAA,+BAAA,+BADA,uBAAA,uBAAA,sBAAA,sBAeM,QAAS,EASf,qBAAA,2BAAA,2BAAA,iCAKI,YK4CW,KLvCf,aACE,YOhBkB,MPepB,oBmBlCI,QAAS,MACT,MAAO,KnBiCX,kBAAA,wBAAA,0BAYI,YO3BgB,KPsHpB,YAjCA,mCAjDA,4BA6HI,YAAa,EA7HjB,mEoBzCI,2BpB6C6B,EoB5C7B,wBpB4C6B,EAIjC,6CACA,8CoBpCI,0BpBqC0B,EoBpC1B,uBpBoC0B,EAU9B,mEAAA,oEoB7DI,2BpBgE6B,EoB/D7B,wBpB+D6B,EAGjC,oEoBrDI,0BpBsD0B,EoBrD1B,uBpBqD0B,EAI9B,mCACA,iCACE,QAAS,EAgBX,4BACE,cAAe,QACf,aAAc,QAVhB,0CAiBA,+BACE,cAAe,QACf,aAAc,QAlBhB,0CAqBA,+BACE,cAAe,SACf,aAAc,SAvBhB,0BA4CA,eACE,aKyEuB,KAAA,KLxEF,EAGvB,kCAAA,uBACE,aAAc,EKoES,KAAA,KL3DzB,yBAAA,+BAAA,oCAII,QAAS,MACT,MAAO,KACP,MAAO,KACP,UAAW,KAPf,sCmB5JI,QAAS,MACT,MAAO,KnB2JX,oCAeM,MAAO,KAfb,8BAAA,oCAAA,oCAAA,0CAuBI,WK1GW,KL2GX,YAAa,EAIjB,sDoBnKI,2BpBwK8B,EoBvK9B,0BpBuK8B,EALlC,sDoBjLI,wBpByL2B,EoBxL3B,uBpBwL2B,EAM/B,4EAAA,6EoBjLI,2BpBoL8B,EoBnL9B,0BpBmL8B,EAGlC,6EoBrMI,wBpBsMyB,EoBrMzB,uBpBqMyB,EIyvE7B,gDADA,6CAGA,2DADA,wDJruEM,SAAU,SACV,KAAM,cACN,eAAgB,KH5NtB,gBcPA,aAiJA,iBAAA,sBdzIE,SAAU,ScRZ,aAEE,MAAO,KAGL,QAAS,KALb,2BAgBI,SAAU,SACV,QAAS,EAMP,KAAM,EAQR,cAAe,EA/BnB,kCAAA,iCAAA,iCAiJA,6BAAA,4BAAA,4BAgBM,QAAS,EAlHf,mBACA,iBAIE,YAAa,OACb,eAAgB,OAyBlB,mBACE,QJ9C4B,IADA,KIgD5B,cAAe,EACf,UN8De,KM7Df,YAAa,IACb,YN+M+B,KM9M/B,MJhFiB,QIiFjB,WAAY,OACZ,iBJ/EkB,QIgFlB,ONfa,IMemB,MJlEd,QarBhB,cboCqB,IyBtBzB,YClBA,OrBKA,KqBFE,Y5ByyB4B,IM1tB9B,mCAVA,mCACA,wDAuBI,QN4N6B,OADA,MM1N7B,UNoDa,QejJb,cbmBiB,II2DrB,mCAfA,mCACA,wDAiCI,QN0N6B,OADA,OMxN7B,UN8Ca,QehJb,cbmBiB,II2DrB,wCAAA,qCA4BI,WAAY,EAUhB,4CACA,oCAKA,oEADA,+EAHA,uCACA,kDACA,mDS3GI,2BT8G2B,ES7G3B,wBT6G2B,EAE/B,oCACE,aAAc,EAEhB,6CACA,qCACA,wCACA,mDACA,oDAEA,oEADA,yDS1GI,0BT4G0B,ES3G1B,uBT2G0B,EAE9B,mDACE,YAAa,EAOf,iBAIE,UAAW,EAJb,2BAYM,YNrFS,KMyEf,uCAAA,6CAwBM,aNjGS,KMyEf,wCAAA,8CA8BM,QAAS,EACT,YNxGS,KMyEf,qDAAA,oDAAA,oDAAA,+CAAA,8CAAA,8CAkCQ,QAAS,Ed5KjB,gBAEE,QAAS,aACT,aQ8TwB,OR7TxB,OAAQ,QAJV,gCAOI,YQ2TsB,KRvT1B,sBACE,SAAU,SACV,QAAS,GACT,QAAS,EAHX,wDAMI,MQ6T0C,KR5T1C,iBQ6T0C,QRpU9C,sDAaI,WQ0TwC,EAAE,EAAE,EAAE,QAAQ,KAAM,EAAE,EAAE,EAAE,MAAM,QRvU5E,uDAiBI,MQwTyC,KRvTzC,iBQwTyC,QR1U7C,yDAwBM,OQ4R2B,YR3R3B,iBQuSuC,KRhU7C,2DA6BM,MQoSuC,QRnSvC,OQsR2B,YR7QjC,0BACE,SAAU,SACV,IAAK,OACL,KAAM,EACN,QAAS,MACT,MQ8QoC,KR7QpC,OQ6QoC,KR5QpC,eAAgB,KAChB,YAAa,KACb,iBQ2QoC,KR1QpC,kBAAmB,UACnB,oBAAqB,OAAA,OACrB,gBQyQoC,IAAI,IR5I1C,aA9DA,eAgEE,QAAS,aAQT,UAAW,KA/Hb,2CuB7EI,cbmBiB,IV0DrB,yEAMI,iBQ6Q2B,uMRnR/B,+EAUI,iBQ2Q+B,QR1Q/B,iBQ4QiC,oJRnQrC,wCAEI,cQoQkB,IRtQtB,sEAMI,iBQiQwB,iJRvP5B,yCAEI,MAAO,KACP,MAAO,KAHX,yDAMM,YAAa,EAanB,eAKE,QUxG4B,IVwGO,KUxGP,IADA,KV0G5B,cU1G4B,OV2G5B,MUvIiB,QVwIjB,eAAgB,OAChB,WU3G6B,4NV2G0B,MAAU,KU7GrC,OAEC,UF6UI,KRjOjC,iBAAkB,OAClB,gBQkOiC,KAAK,KRjOtC,OU5HkB,IV4HkB,MU3HlB,QarBhB,cboCqB,IV+GvB,gBAAiB,KAfnB,qBAmBI,aQmO+B,WRlO/B,QAAS,EApBb,gCA6BM,MU7Ja,QV8Jb,iBQkI2B,KRhKjC,wBAmCI,MUjKc,QVkKd,OQ8J6B,YR7J7B,iBUlKgB,QV6HpB,2BA0CI,QAAS,EAIb,kBACE,YUlJ4B,IVmJ5B,eUnJ4B,IVoJ5B,UQyM2B,IR5L7B,aACE,SAAU,SAGV,OQ0L6B,ORzL7B,OAAQ,QAeV,qBAAA,6BAuBI,SAAU,SAMV,OQ6I2B,OR5I3B,QQgJwB,MACA,KRhJxB,YQiJwB,IRhJxB,MQiJwB,KR7L5B,mBACE,UQsL6B,MRrL7B,UAAW,KACX,OAAQ,EACR,OAAQ,iBACR,QAAS,EAOX,qBAEE,IAAK,EACL,MAAO,EACP,KAAM,EACN,QAAS,EAKT,YAAa,KACb,iBQuK0B,KRtK1B,OQ1Ja,IR0JqB,MQwKR,Ke1YxB,cbmBiB,IVmMrB,qCAkBM,QQyKc,iBR3LpB,6BAwBI,IQtKW,KRuKX,MQvKW,KRwKX,OQxKW,KRyKX,QAAS,EACT,QAAS,MAKT,iBQuJwB,KRtJxB,OQhLW,IRgLuB,MQkJV,Ke1YxB,cvByPuB,EUtON,IAAA,IVsO8D,EqC5NnF,sBAtBA,UAwBI,QAAS,arCuLb,sCAwCM,QQsJc,S6BhTpB,kBAvDA,iBR5CA,ePHI,QAAS,GAET,MAAO,KeCX,KACE,aAAc,EACd,cAAe,EACf,WAAY,KAGd,gBAAA,gBAII,gBAAiB,KAJrB,mBASI,M3BVc,Q2BClB,mBAAA,yBAAA,yBAYM,M3BbY,Q2BcZ,O7BkT2B,Y6BjT3B,iB7Bie0B,Y6BzdhC,gCAAA,gCAOI,Y7B6c4B,K6B7YhC,+BAvDA,8BA8DM,Y7BqY0B,M6BnchC,iBf9CI,QAAS,Me8Cb,oBAOI,c7Bqc0C,E6B5c9C,oBAeI,QAAS,MACT,Q7Bqb4B,KAAK,I6BpbjC,O7B2b0C,E6B3bX,MAAM,YdxDrC,wBfof0C,Eenf1C,uBfmf0C,E6B7c9C,0BAAA,0BAqBM,a3B3Dc,QAAA,QFif0B,K6B3c9C,6BAAA,mCAAA,mCA0BQ,M3BjEU,Q2BkEV,iBAAkB,YAClB,aAAc,YA5BtB,mCAAA,yCAAA,yCAAA,2BAAA,iCAAA,iCAoCM,M3B5EW,Q2B6EX,iB3B3Ec,Q2B4Ed,a7B2awC,KAAA,K6B3awD,YAtCtG,yBA4CI,W7Bga0C,Eenf1C,wBcqF2B,EdpF3B,uBcoF2B,EAS/B,kBfrGI,QAAS,MeqGb,qBAII,MAAO,KAJX,qBAYI,QAAS,MACT,Q7BiY4B,KAAK,IelfjC,cbmBiB,I2BiFrB,oCAAA,0CAAA,0CAAA,4BAAA,kCAAA,kCAoBM,M3BpHa,Q2BqHb,OAAQ,QACR,iB3BnHc,Q2BwHpB,uBAEI,QAAS,MACT,MAAO,KAHX,iCAMM,W7B2W0B,M6B1W1B,YAAa,EAWnB,uBAEI,QAAS,KAFb,qBAKI,QAAS,MRrJb,QACE,SAAU,SACV,QrBgdkC,EqBldpC,ePFI,QAAS,MOmBb,aACE,QrBkbyB,KqBza3B,qBADA,kBAEE,SAAU,MACV,MAAO,EACP,KAAM,EACN,QrByayB,KqBja3B,kBACE,IAAK,EAGP,qBACE,OAAQ,EAGV,mBACE,SAAU,OACV,IAAK,EACL,QrBuZyB,KqBtZzB,MAAO,KLXL,yBKxCJ,QNDI,cbmBiB,ImBSrB,qBADA,kBATA,aA8BA,mBNhDI,cMsBuB,GA2C3B,cACE,MAAO,KACP,YrBkZkC,OqBjZlC,erBiZkC,OqBhZlC,aAAc,KACd,UrB0Ee,QqBzEf,YAAa,QANf,oBAAA,oBASI,gBAAiB,KAKrB,gBACE,MAAO,KACP,MrBTa,IqBUb,YrBqYkC,EqBpYlC,erBoYkC,EqBnYlC,arB8XkC,EqB7XlC,YrB6XkC,EqBnYpC,wBAUI,QAAS,QAsCb,6BAgJA,6BAAA,6BAhJA,6BAgJA,6BPjRI,QAAS,GAET,MAAO,KOkGX,aACE,QAAS,aACT,YAAgB,QAChB,eAAgB,QASlB,gBACE,MAAO,MACP,OAAQ,IACR,QrB6WmC,MADA,OqB3WnC,UrB8Be,QqB7Bf,YAAa,EACb,WAAY,OAAA,OAAA,UACZ,gBAAiB,KAAA,KACjB,OrB9Ca,IqB8CS,MAAM,YNtH1B,cboCqB,ImB0EzB,sBAAA,sBAYI,gBAAiB,KLpEjB,yBKyEJ,oCASU,QAAS,MACT,MAAO,KACP,WAAY,MACZ,aAAc,EAZxB,kCAgBU,WAAY,MACZ,cAAe,MAjBzB,iDAoBY,SAAU,OACV,MAAO,ML3Gf,yBKsFJ,sBA2BQ,QAAS,OLpGb,yBKyEJ,oCASU,QAAS,MACT,MAAO,KACP,WAAY,MACZ,aAAc,EAZxB,kCAgBU,WAAY,MACZ,cAAe,MAjBzB,iDAoBY,SAAU,OACV,MAAO,ML3Gf,yBKsFJ,sBA2BQ,QAAS,OLpGb,yBKyEJ,oCASU,QAAS,MACT,MAAO,KACP,WAAY,MACZ,aAAc,EAZxB,kCAgBU,WAAY,MACZ,cAAe,MAjBzB,iDAoBY,SAAU,OACV,MAAO,ML3Gf,yBKsFJ,sBA2BQ,QAAS,OA3BjB,6BPhII,QAAS,MEuDT,0BKyEJ,oCASU,QAAS,MACT,MAAO,KACP,WAAY,MACZ,aAAc,EAZxB,kCAgBU,WAAY,MACZ,cAAe,MAjBzB,iDAoBY,SAAU,OACV,MAAO,ML3Gf,0BKsFJ,sBA2BQ,QAAS,OA3BjB,sBA2BQ,QAAS,MA3BjB,6BPhII,QAAS,MOgIb,oCASU,QAAS,MACT,MAAO,KACP,WAAY,MACZ,aAAc,EAZxB,kCAgBU,WAAY,MACZ,cAAe,MShJzB,MAeA,YACE,c5BwD0B,ImBuD5B,iDAoBY,SAAU,OACV,MAAO,KAkBnB,sBAEI,MAAO,KAFX,sBAMI,QAAS,MACT,YAAgB,QAChB,eAAgB,QARpB,gCAAA,gCAWM,YAAa,KAUnB,4BAAA,kCAAA,kCAAA,8BAAA,oCAAA,oCAGI,MnB1Le,QmBuLnB,oCAYM,MnBlMW,QmBsLjB,4CAAA,kDAAA,kDAAA,2CAAA,iDAAA,iDAAA,yCAAA,+CAAA,+CAAA,0CAAA,0CAAA,0CAAA,gDAAA,gDAeQ,MnBtMW,QmBuLnB,8BA8BI,iBrBkRsB,yOqBjRtB,arBkRgC,eqBjTpC,8BAmCI,iBAAkB,iBAKtB,2BAAA,iCAAA,iCAAA,6BAAA,mCAAA,mCAGI,MrB4PgC,KqB/PpC,mCAYM,MrBiP8B,qBqB7PpC,yCAAA,yCAeQ,MrB+O4B,sB+BxclC,+BAFA,2BADA,2BAEA,0BV2MF,2CAAA,iDAAA,iDAAA,0CAAA,gDAAA,gDAAA,wCAAA,8CAAA,8CAAA,yCAAA,+CAAA,+CUzMI,MAAO,KVyMX,6BA8BI,iBrBmOqB,0PqBlOrB,arBmOgC,qBqBlQpC,6BAmCI,iBAAkB,uBAStB,6BPhRI,QAAS,MEuDT,yBKyNJ,4CAKQ,MAAO,KACP,YAAa,GL5OjB,yBKsOJ,sBAUM,QAAS,iBAVf,6BPhRI,QAAS,MEuDT,yBKyNJ,4CAkBQ,MAAO,KACP,YAAa,GLzPjB,yBKsOJ,sBAuBM,QAAS,iBAvBf,6BPhRI,QAAS,MEuDT,yBKyNJ,4CA+BQ,MAAO,KACP,YAAa,GW1SrB,iBCmCA,WAEE,MAAO,KjBDL,yBKsOJ,sBAoCM,QAAS,iBSnTf,MACE,SAAU,SACV,QAAS,MAET,iB9BmkByB,KevkBvB,cbmBiB,I4BZnB,O5BakB,I4BbS,M5BcT,Q4BXpB,mBAmEA,oBAZA,oBhBlEI,QAAS,MADT,QAAS,GAET,MAAO,KgBUX,YAEE,Q5BKa,K4B4Df,aAZA,aAcE,Q5BP0B,IAvDb,K4B+Db,iB9BsfyB,Q8BrgB3B,aA9CA,eAKA,sBA4CE,cAAe,EAjDjB,eACE,WAAc,OAgBhB,iBAEI,gBAAiB,KAFrB,sBAMI,Y5BzBW,K4BmFf,mBAPA,kBAQE,aAAgB,MAChB,YAAe,MAxDjB,2DfxCI,wBbaiB,IaZjB,uBbYiB,I4B2BrB,yDf1BI,2BbDiB,IaEjB,0BbFiB,I4B8CrB,aAKE,c5BlDkB,I4BkDgB,M5BjDhB,Q4B4CpB,yBfjEI,cfqkBuB,gBAAA,gB8B5foD,EAAE,EAIjF,aAIE,W5B7DkB,I4B6Da,M5B5Db,Q4BwDpB,wBf7EI,ceoFuB,EAAE,E9BifF,gBAAA,gB8Bxe3B,kBAEE,c5BvB0B,K4ByB1B,cAAe,EAajB,cC/GE,iB7BHU,Q6BIV,a7BJU,Q6BOV,2BADA,2BAEE,iBAAkB,YD6GtB,cClHE,iB7BDW,Q6BEX,a7BFW,Q6BKX,2BADA,2BAEE,iBAAkB,YDgHtB,WCrHE,iB/B0B0B,Q+BzB1B,a/ByB0B,Q+BtB1B,wBADA,wBAEE,iBAAkB,YDmHtB,cCxHE,iB7BCY,Q6BAZ,a7BAY,Q6BGZ,2BADA,2BAEE,iBAAkB,YDsHtB,aC3HE,iB7BES,Q6BDT,a7BCS,Q6BET,0BADA,0BD4IF,qBATA,mBANA,sBAGA,wBAMA,sBAGA,sBClIE,iBAAkB,YDsHpB,sBCrHE,a7B+BkC,Q4ByFpC,wBCxHE,a7BmCgC,Q4BwFlC,mBC3HE,a7BqC+B,Q4ByFjC,sBC9HE,a7BwCkC,Q4ByFpC,sBCjIE,a7BVY,Q4B8Id,qBCpIE,a7B2CiC,Q6BlCjC,2BADA,2BAEE,aAAc,qBAWC,kDAHjB,yBAEA,6BADA,yBAGE,MAAO,sBAET,+BAAA,+BAEI,M/BqiBqB,K8B3a3B,iBACE,QAAS,EACT,cAAe,EACf,YAAa,EAIf,UfrKI,cfqkBuB,gB8B5Z3B,kBACE,SAAU,SACV,IAAK,EACL,MAAO,EACP,OAAQ,EACR,KAAM,EACN,Q9B4ZyB,Q8BtZ3B,cf/KI,wBf+jBuB,gBe9jBvB,uBf8jBuB,gB8B7Y3B,iBfpKI,2BfijBuB,gBehjBvB,0BfgjBuB,gBgB5hBvB,yBc+JA,WACE,QAAS,KACT,UAAW,IAAA,KACX,a9BkYqB,S8BjYrB,c5BpIsB,I4BqItB,Y9BgYqB,S8BrYvB,iBAQI,KAAM,EAAA,EAAA,EACN,a9B4XmB,Q8B3XnB,cAAe,EACf,Y9B0XmB,Q8B1VzB,YAEI,QAAS,KACT,UAAW,IAAA,KAHf,kBAYM,KAAM,EAAA,EAAA,EAZZ,wBAmBM,YAAa,EACb,YAAa,EApBnB,8BftOE,2BegQmC,Ef/PnC,wBe+PmC,EA1BrC,4CA6BU,wBAAyB,EA7BnC,+CAgCU,2BAA4B,EAhCtC,6BfxNE,0Be4PkC,Ef3PlC,uBe2PkC,EApCpC,2CAuCU,uBAAwB,EAvClC,8CA0CU,0BAA2B,EA1CrC,qDAAA,sEAAA,mEA+CQ,cAAe,EAkBvB,cACE,aAAc,EACd,W9ByR4B,Q8B3R9B,oBAKI,QAAS,aACT,MAAO,ME9Tb,YCAA,YAIE,cjCmDS,KenDP,cbmBiB,I8BvBrB,YACE,QhCgwB8B,OACA,KgC/vB9B,WAAY,KACZ,iB9BOkB,Q8BXpB,mBlBEI,QAAS,GACT,QAAS,MACT,MAAO,KkBKX,0CAKI,QAAS,aACT,chCovB4B,MgCnvB5B,ahCmvB4B,MgClvB5B,M9BPc,Q8BQd,QAAS,IATb,gDAsBI,gBAAiB,KAtBrB,wBA0BI,M9BzBc,Q+BVlB,YACE,QAAS,aACT,aAAc,EACd,WjCoDS,KiC/CX,WACE,QAAS,OADX,kCAKM,YAAa,ElBkBf,0BbRiB,IaSjB,uBbTiB,I+BfrB,iClBSI,2BbMiB,IaLjB,wBbKiB,I+BfrB,6BAAA,mCAAA,mCAiBM,QAAS,EACT,MjCogBiC,KiCngBjC,OAAQ,QACR,iB/B5BM,Q+B6BN,a/B7BM,Q+BQZ,+BAAA,qCAAA,qCA2BM,M/BzBY,Q+B0BZ,eAAgB,KAChB,OjCqS2B,YiCpS3B,iBjC6fiC,KiC5fjC,ajC6fiC,KiCxfvC,WACE,SAAU,SAEV,QjC+doC,MADA,OiC7dpC,YAAa,KACb,M/BjDU,Q+BkDV,gBAAiB,KACjB,iBjCmeqC,KiClerC,OjCwBa,IiCxBoB,MjCoeI,KkC9gBjC,iDAAA,iDnBqBF,0BbRiB,IaSjB,uBbTiB,IgCRf,gDAAA,gDnBEF,2BbMiB,IaLjB,wBbKiB,I+BqBrB,iBAAA,iBAWI,MjCsCoB,QiCrCpB,iB/B7CgB,Q+B8ChB,ajCmemC,KkCzhBrC,0BACE,QlC8gBkC,OADA,OkC5gBlC,UlC+Ia,QkCjJf,0BACE,QlC4gBkC,QADA,OkC1gBlC,UlCgJa,QOhJjB,KACE,QAAS,aACT,QPkoB0B,MADA,KOhoB1B,UP8nB0B,IO5nB1B,YAAa,EACb,MPynB0B,KOxnB1B,WAAY,OAEZ,eAAgB,SQVd,cbmBiB,IKlBrB,WAcI,QAAS,KAKb,UACE,SAAU,SACV,IAAK,KAKP,YAAA,YAEI,MPomBwB,KOnmBxB,gBAAiB,KACjB,OAAQ,QASZ,UACE,cP8lB0B,KO7lB1B,aP6lB0B,KevoBxB,cf0oBwB,MOxlB5B,a4BnDE,iBjCOgB,QK4ClB,yBAAA,yB4B/CM,iBAAkB,Q5BmDxB,a4BvDE,iBjCHU,QK0DZ,yBAAA,yB4BnDM,iBAAkB,Q5BuDxB,a4B3DE,iBjCDW,QK4Db,yBAAA,yB4BvDM,iBAAkB,Q5B2DxB,U4B/DE,iBnC0B0B,QOqC5B,sBAAA,sB4B3DM,iBAAkB,Q5B+DxB,a4BnEE,iBjCCY,QKkEd,yBAAA,yB4B/DM,iBAAkB,Q5BmExB,Y4BvEE,iBjCES,QKqEX,wBAAA,wB4BnEM,iBAAkB,QCPxB,WACE,QpCwiB+B,KoCxiBF,KAC7B,cpCuiB+B,KoCtiB/B,iBlCQkB,QaPhB,cbmBiB,IyBnBrB,OUUA,UAIE,crCqCS,KgBVP,yBoB7CJ,WAOI,QAAU,KpCkiBmB,MoC9hBjC,cACE,iBAAkB,QAGpB,iBACE,cAAe,EACf,aAAc,ErBbZ,cqBcqB,ETdzB,OACE,Q3B6qB4B,OADA,Q2B1qB5B,O3BqEa,I2BrEe,MAAM,YZHhC,cbmBiB,IyBXrB,eAEE,MAAO,QAaT,mBACE,cAAgB,OADlB,0BAKI,SAAU,SACV,IAAK,SACL,M3B+oB0B,S2B9oB1B,MAAO,QASX,eWzCE,iBtC+iB+B,QsC9iB/B,atC+iB+B,QsC9iB/B,MtC4iB+B,QsC1iB/B,kBACE,iBAAkB,QAEpB,2BACE,MAAO,QXoCX,YW5CE,iBtCmjB+B,QsCljB/B,atCmjB+B,QsCljB/B,MtCgjB+B,QsC9iB/B,eACE,iBAAkB,QAEpB,wBACE,MAAO,QXuCX,eW/CE,iBtCujB+B,QsCtjB/B,atCwjB+B,QsCvjB/B,MtCojB+B,QsCljB/B,kBACE,iBAAkB,QAEpB,2BACE,MAAO,QX0CX,cWlDE,iBtC4jB+B,QsC3jB/B,atC4jB+B,QsC3jB/B,MtCyjB+B,QsCvjB/B,iBACE,iBAAkB,QAEpB,0BACE,MAAO,QDPX,gCACE,KAAO,oBrCkDE,KqClD6B,EACtC,GAAK,oBAAqB,EAAA,GAQ5B,UACE,QAAS,MACT,MAAO,KACP,OrCsCS,KqCnCX,iBAEE,iBrCorB4B,KqClrB5B,OAAQ,EAER,WAAY,KtBtBV,cbmBiB,ImCSrB,2BACE,iBrC0qB4B,QqCxqB5B,OAAQ,EAEV,oCACE,iBrCqqB4B,Qe5qB1B,0BbRiB,IaSjB,uBbTiB,ImCkBrB,yCACE,iBrCiqB4B,Qe5qB1B,0BbRiB,IaSjB,uBbTiB,ImCuBrB,0CtB7BI,2BbMiB,IaLjB,wBbKiB,ImC0BrB,+CtBhCI,2BbMiB,IaLjB,wBbKiB,ImC+BrB,uCACE,iBrCmpB4B,KetsB1B,cbmBiB,ImCqCrB,iBADA,wBAEE,iBrC6oB4B,KetsB1B,cbmBiB,ImCmErB,iDEjDE,iBAAkB,iKFmDlB,gBrCrCS,KAAA,KqCuCX,4CErDE,iBAAkB,iKFuDlB,gBrCzCS,KAAA,KqC2CX,mCEzDE,iBAAkB,iKF2DlB,gBrC7CS,KAAA,KqC4DX,kDACE,UAAW,qBAAA,GAAA,OAAA,SAEb,6CACE,UAAW,qBAAA,GAAA,OAAA,SAGb,kCAtDE,UACE,iBrCqoB0B,KetsB1B,cbmBiB,ImCkDnB,cACE,QAAS,aACT,OrCpBO,KqCqBP,YAAa,QACb,iBrC8nB0B,Qe5qB1B,0BbRiB,IaSjB,uBbTiB,ImCyDnB,wBtB/DE,2BbMiB,IaLjB,wBbKiB,ImCiFnB,sBE/DA,iBAAkB,iKFiEhB,gBrCnDO,KAAA,KqCoET,yCACE,UAAW,qBAAA,GAAA,OAAA,SG1GX,gCACE,iBtCjBO,SmCmIb,iDGjII,iBtCFS,QmCmIb,4CG7HI,iBtCNS,QmCmIb,mCGxHI,iBtCXS,QmCsIb,8CGpII,iBxCyBwB,QqC2G5B,yCGhII,iBxCqBwB,QqC2G5B,gCG3HI,iBxCgBwB,QwCZ1B,kCACE,6BACE,iBxCUsB,QwCXxB,gCACE,iBtCfQ,SmCuId,iDGvII,iBtCAU,QmCuId,4CGnII,iBtCJU,QmCuId,mCG9HI,iBtCTU,QmC0Id,gDG1II,iBtCCO,QmCyIX,2CGtII,iBtCHO,QmCyIX,kCGjII,iBtCRO,QsCYT,kCACE,+BACE,iBtCdK,SuCJT,OACE,QAAS,KAEX,YACE,KAAM,EAER,cACE,WAAY,OAEd,cACE,WAAY,SA6BhB,cACE,QAAS,MADX,4BAKI,UAAW,KASf,aACE,azCwtB4B,KyCrtB9B,YACE,czCotB4B,KyC5sB9B,eACE,WAAY,EACZ,czCysB6B,IyCjsB/B,YACE,aAAc,EACd,WAAY,KC3Ed,YAEE,aAAc,EACd,cAAe,EAQjB,iBACE,SAAU,SACV,QAAS,MACT,QxCGa,KwCDb,cxCIkB,KwCHlB,iB1CmsB8B,K0ClsB9B,OxCEkB,IwCFe,MxCZjB,QwCKlB,6B3BLI,wBfitB4B,EehtB5B,uBfgtB4B,E0C5sBhC,4BAcI,cAAe,E3BLf,2BfmsB4B,EelsB5B,0BfksB4B,E0C5sBhC,0BAAA,gCAoBM,MxCzBY,QwC0BZ,O1CsS2B,Y0CrS3B,iBxC1Bc,QwCIpB,mDAAA,yDA0BQ,MAAO,QA1Bf,gDAAA,sDA6BQ,MxClCU,QwCKlB,gCAoBM,MxCzBY,QwC0BZ,O1CsS2B,Y0CrS3B,iBxC1Bc,QwCIpB,yDA0BQ,MAAO,QA1Bf,sDA6BQ,MxClCU,QwCKlB,wBAAA,8BAoCM,QAAS,EACT,MxC5Ca,QwC6Cb,gBAAiB,KACjB,iBxC3Cc,QwC4Cd,axC5Cc,QwCIpB,iDAAA,wDAAA,uDAAA,uDAAA,8DAAA,6DA8CQ,MAAO,QA9Cf,8CAAA,oDAiDQ,M1CiqBwB,K0CltBhC,8BAoCM,QAAS,EACT,MxC5Ca,QwC6Cb,gBAAiB,KACjB,iBxC3Cc,QwC4Cd,axC5Cc,QwCIpB,uDAAA,8DAAA,6DA8CQ,MAAO,QA9Cf,oDAiDQ,M1CiqBwB,K0C3pBhC,mCAEI,aAAc,EACd,YAAa,EACb,cAAe,EAUnB,wBACE,MAAO,KACP,M1CipB8B,K0ChpB9B,WAAY,QCiBZ,OAAQ,QDpBV,iDAMI,M1C+oB4B,K0CrpBhC,8BAAA,8BAWI,M1CwoB4B,K0CvoB5B,gBAAiB,KACjB,iBxCrFiB,Q0CTnB,yBACE,M5C6iB6B,Q4C5iB7B,iB5C6iB6B,Q4C1iB/B,0BACA,+BAAE,M5CwiB6B,Q4CziB/B,mDACA,wDAGI,MAAO,QAJX,gCAAA,gCACA,qCAAA,qCAOI,M5CiiB2B,Q4ChiB3B,iBAAkB,QATtB,iCAAA,uCAAA,uCACA,sCAAA,4CAAA,4CAaM,MAAO,KACP,iB5C0hByB,Q4CzhBzB,a5CyhByB,Q4C9iB/B,sBACE,M5CijB6B,Q4ChjB7B,iB5CijB6B,Q4C9iB/B,uBACA,4BAAE,M5C4iB6B,Q4C7iB/B,gDACA,qDAGI,MAAO,QAJX,6BAAA,6BACA,kCAAA,kCAOI,M5CqiB2B,Q4CpiB3B,iBAAkB,QATtB,8BAAA,oCAAA,oCACA,mCAAA,yCAAA,yCAaM,MAAO,KACP,iB5C8hByB,Q4C7hBzB,a5C6hByB,Q4CljB/B,yBACE,M5CqjB6B,Q4CpjB7B,iB5CqjB6B,Q4CljB/B,0BACA,+BAAE,M5CgjB6B,Q4CjjB/B,mDACA,wDAGI,MAAO,QAJX,gCAAA,gCACA,qCAAA,qCAOI,M5CyiB2B,Q4CxiB3B,iBAAkB,QATtB,iCAAA,uCAAA,uCACA,sCAAA,4CAAA,4CAaM,MAAO,KACP,iB5CkiByB,Q4CjiBzB,a5CiiByB,Q4CtjB/B,wBACE,M5C0jB6B,Q4CzjB7B,iB5C0jB6B,Q4CvjB/B,yBACA,8BAAE,M5CqjB6B,Q4CtjB/B,kDACA,uDAGI,MAAO,QAJX,+BAAA,+BACA,oCAAA,oCAOI,M5C8iB2B,Q4C7iB3B,iBAAkB,QATtB,gCAAA,sCAAA,sCACA,qCAAA,2CAAA,2CAaM,MAAO,KACP,iB5CuiByB,Q4CtiBzB,a5CsiByB,Q0CzcjC,yBACE,WAAY,EACZ,c1CsnBsC,I0CpnBxC,sBACE,cAAe,EACf,YAAa,IvBzHf,kBACE,SAAU,SACV,QAAS,MACT,OAAQ,EACR,QAAS,EAJX,yCAAA,wBAAA,yBAAA,yBAAA,wBAYI,SAAU,SACV,IAAK,EACL,OAAQ,EACR,KAAM,EACN,MAAO,KACP,OAAQ,KACR,OAAQ,EAIZ,wBACE,eAAgB,UAGlB,wBACE,eAAgB,OAGlB,uBACE,eAAgB,IAGlB,uBACE,eAAgB,KSrClB,OACE,MAAO,MACP,UAAY,OAEZ,YAAa,EACb,M5BwyB4B,K4BvyB5B,Y5BwyB4B,EAAE,IAAI,EAAE,K4BvyBpC,QAAS,GiBPX,SCCA,SCAE,Y/C0IuB,eAAgB,cAAe,mBAAoB,WAAY,OAAQ,iBAAkB,MAAO,W+CxIvH,WAAY,OAEZ,eAAgB,OAChB,WAAY,KACZ,Y/CiJiB,I+C7IjB,YAAa,KACb,eAAgB,KAChB,YAAa,OACb,WAAY,OACZ,aAAc,OFJd,U7C0Ie,Q6CxIf,UAAW,WGsGT,gBAAiB,KCvFE,YAAa,IrB5BpC,aAAA,aAUI,M5BmyB0B,K4BlyB1B,gBAAiB,KACjB,OAAQ,QACR,QAAS,GAUb,aACE,QAAS,EACT,OAAQ,QACR,eACA,OAAQ,EACR,mBAAoB,KRoBtB,eyBhDA,SAeE,gBAAiB,YzBHnB,OACE,SAAU,MACV,IAAK,EACL,MAAO,EACP,OAAQ,EACR,KAAM,EACN,QpB8byB,KoB7bzB,QAAS,KAIT,QAAS,EA6EX,qBAxBA,qBNzEI,QAAS,M+BqKX,QAAS,G/BpKP,MAAO,KMQX,0BAkBI,WAAY,UAAA,IAAA,SACZ,UAAW,kBAnBf,wBAqBuB,UAAW,eAElC,mBACE,WAAY,OACZ,WAAY,KAId,cACE,SAAU,SACV,MAAO,KACP,OpBymB4B,KoBrmB9B,eACE,SAAU,SACV,iBpBymB+B,KoBvmB/B,OpBwBa,IoBxBuB,MpBwmBL,eexpB7B,cbmBiB,IkBiCnB,QAAS,EAIX,gBACE,SAAU,MACV,IAAK,EACL,MAAO,EACP,OAAQ,EACR,KAAM,EACN,QpB6YyB,KoB5YzB,iBpB8lB4B,KoBrmB9B,qBAUW,QAAS,EAVpB,mBAWS,QpB2lBqB,GoBtlB9B,cACE,QpB2kB4B,KoB1kB5B,cpBFa,IoBE6B,MpBqlBd,QoBjlB9B,qBACE,WAAY,KAId,aACE,OAAQ,EACR,YpB+DiB,IoB1DnB,YACE,SAAU,SACV,QpBmjB4B,KoB/iB9B,cACE,QpB8iB4B,KoB7iB5B,WAAY,MACZ,WpB3Ba,IoB2B0B,MpB4jBX,Q6CnqB9B,SCCA,SAGE,QAAS,MDuJT,SAAU,SzB/CZ,yBACE,SAAU,SACV,IAAK,QACL,MAAO,KACP,OAAQ,KACR,SAAU,OJpER,yBI0EF,cACE,UpBijB0B,MoBhjB1B,OpB6hB0B,KoB7hBW,KAOvC,UAAY,UpB0iBgB,OgB7nB1B,yBIuFF,UAAY,UpBoiBgB,O8CvqB9B,SAEE,Q9CycyB,K+CpczB,WAAY,KACZ,WAAY,MDEZ,QAAS,EAVX,YAYS,Q9C8kBqB,G8C1lB9B,2CAAA,qBAgBI,Q9C+kB0B,I8C/kBI,EAC9B,W9C4kB0B,K8C7lB9B,kEAAA,4CAoBM,OAAQ,EACR,KAAM,IACN,Y9CykBwB,K8CxkBxB,QAAS,GACT,a9CukBwB,IAAA,I8CvkBgC,EACxD,iB5CnBc,K4CNpB,yCAAA,uBA8BI,QAAS,E9CikBiB,I8ChkB1B,Y9C8jB0B,I8C7lB9B,gEAAA,8CAkCM,IAAK,IACL,KAAM,EACN,W9C2jBwB,K8C1jBxB,QAAS,GACT,a9CyjBwB,IAAA,IAAA,I8CzjBqD,EAC7E,mB5CjCc,K4CNpB,wCAAA,wBA4CI,Q9CmjB0B,I8CnjBI,EAC9B,W9CgjB0B,I8C7lB9B,+DAAA,+CAgDM,IAAK,EACL,KAAM,IACN,Y9C6iBwB,K8C5iBxB,QAAS,GACT,aAAc,E9C2iBU,IAAA,I8C1iBxB,oB5C/Cc,K4CNpB,0CAAA,sBA0DI,QAAS,E9CqiBiB,I8CpiB1B,Y9CkiB0B,K8C7lB9B,iEAAA,6CA8DM,IAAK,IACL,MAAO,EACP,W9C+hBwB,K8C9hBxB,QAAS,GACT,a9C6hBwB,I8C7hBW,E9C6hBX,IAAA,I8C5hBxB,kB5C7Dc,K4CmEpB,eACE,U9C6gB4B,M8C5gB5B,Q9CghB4B,IACA,I8ChhB5B,M9C4gB4B,K8C3gB5B,WAAY,OACZ,iB5CxEkB,KaHhB,cbmBiB,I4CmDrB,uBASI,SAAU,SACV,MAAO,EACP,OAAQ,EACR,aAAc,YACd,aAAc,MDvFlB,SAEE,IAAK,EACL,KAAM,EACN,Q7CucyB,K6CrczB,U7CkmBoC,M6CjmBpC,Q7C+lBoC,I+C9lBpC,WAAY,KACZ,WAAY,MFKZ,iB7CylBoC,K6CvlBpC,O7C4Da,I6C5DiB,M7C0lBM,eetmBlC,cbmBiB,I8CkLrB,kBAjHA,kBAyHE,MhDolB4C,KgDnlB5C,WAAY,OACZ,YhDikB4C,EAAE,IAAI,IAAI,e6CpxBxD,2CAAA,qBAyBI,W7C2lBkC,M6CpnBtC,kDAAA,mDAAA,4BAAA,6BA6BM,KAAM,IACN,oBAAqB,EA9B3B,mDAAA,6BAkCM,O7CqlBiC,M6CplBjC,Y7ColBiC,M6CnlBjC,iB7ColBgC,gB6CxnBtC,kDAAA,4BAwCM,OAAU,MACV,Y7C2kBgC,M6C1kBhC,iB7C6jBgC,K6CvmBtC,yCAAA,uBAgDI,Y7CokBkC,K6CpnBtC,gDAAA,iDAAA,8BAAA,+BAoDM,IAAK,IACL,kBAAmB,EArDzB,iDAAA,+BAyDM,K7C8jBiC,M6C7jBjC,W7C6jBiC,M6C5jBjC,mB7C6jBgC,gB6CxnBtC,gDAAA,8BA+DM,KAAQ,MACR,WAAc,MACd,mB7CsiBgC,K6CvmBtC,wCAAA,wBAuEI,W7C6iBkC,K6CpnBtC,+CAAA,gDAAA,+BAAA,gCA2EM,KAAM,IACN,iBAAkB,EA5ExB,gDAAA,gCAgFM,I7CuiBiC,M6CtiBjC,Y7CsiBiC,M6CriBjC,oB7CsiBgC,gB6CxnBtC,+CAAA,+BAsFM,IAAO,MACP,Y7C6hBgC,M6C5hBhC,oB7CqhBgC,Q6C7mBtC,+DAAA,+CA6FM,SAAU,SACV,IAAK,EACL,KAAM,IACN,QAAS,MACT,MAAO,KACP,YAAa,MACb,QAAS,GACT,cAAe,IAAI,M7CygBa,Q6C7mBtC,0CAAA,sBA0GI,Y7C0gBkC,M6CpnBtC,iDAAA,kDAAA,6BAAA,8BA8GM,IAAK,IACL,mBAAoB,EA/G1B,kDAAA,8BAmHM,M7CogBiC,M6CngBjC,W7CmgBiC,M6ClgBjC,kB7CmgBgC,gB6CxnBtC,iDAAA,6BAyHM,MAAS,MACT,WAAc,MACd,kB7C4egC,K6CretC,eACE,Q7C4eoC,IADA,K6C1epC,OAAQ,EACR,U7Cce,K6Cbf,iB7CueoC,Q6CtepC,c7C3Da,I6C2DwB,MAAM,Q9BnIzC,c8BqIsB,OAA2C,OAA0C,EAAE,EAPjH,qBAUI,QAAS,KAIb,iBACE,Q7CieoC,IADA,K6CvdtC,gBADA,iBAEE,SAAU,SACV,QAAS,MACT,MAAO,EACP,OAAQ,EACR,aAAc,YACd,aAAc,MG/JhB,UAIA,gBAMI,SAAU,SHwJd,iBACE,QAAS,GACT,a7CkdqC,K6ChdvC,gBACE,QAAS,GACT,a7C2coC,KgD/mBtC,gBAEE,MAAO,KACP,SAAU,OAHZ,+BAMI,SAAU,SACV,QAAS,KACT,WAAY,IAAA,YAAA,KARhB,qCAAA,mCAcM,YAAa,EAIf,qDAlBJ,+BAmBM,WAAY,UAAA,IAAA,YACZ,oBAAqB,OACrB,YAAa,OArBnB,4CAAA,oCAyBQ,KAAM,EACN,UAAW,sBA1BnB,2CAAA,oCA8BQ,KAAM,EACN,UAAW,uBA/BnB,sCAAA,yCAAA,0CAoCQ,KAAM,EACN,UAAW,oBArCnB,wBAAA,sBAAA,sBA6CI,QAAS,MA7Cb,wBAiDI,KAAM,EAjDV,sBAAA,sBAsDI,SAAU,SACV,IAAK,EACL,MAAO,KAxDX,sBA4DI,KAAM,KA5DV,sBA+DI,KAAM,MA/DV,2BAAA,4BAmEI,KAAM,EAnEV,6BAuEI,KAAM,MAvEV,8BA0EI,KAAM,KASV,kBACE,SAAU,SACV,IAAK,EACL,OAAQ,EACR,KAAM,EACN,MhD0rB4C,IgDzrB5C,UhD4rB4C,KgDxrB5C,QhDurB4C,GgDjsB9C,uBTjFE,iBAAkB,kEAClB,kBAAmB,SACnB,OAAQ,+GS+EV,wBAmBI,MAAO,EACP,KAAM,KTrGR,iBAAkB,kEAClB,kBAAmB,SACnB,OAAQ,+GS+EV,wBAAA,wBA0BI,MhDoqB0C,KgDnqB1C,gBAAiB,KACjB,QAAS,EACT,QAAS,GA7Bb,6BAAA,6BAmCI,SAAU,SACV,IAAK,IACL,QAAS,EACT,QAAS,aACT,MhDwqB0C,KgDvqB1C,OhDuqB0C,KgDtqB1C,WAAc,MACd,YAAa,MACb,YAAa,EA3CjB,6BA8CI,KAAM,IACN,YAAe,MA/CnB,6BAkDI,MAAO,IACP,aAAgB,MAnDpB,qCAwDM,QAAS,QAxDf,qCA6DM,QAAS,QAWf,qBACE,SAAU,SACV,OAAQ,KACR,KAAM,IACN,QAAS,GACT,MhDunB4C,IgDtnB5C,aAAc,EACd,YAAe,KACf,WAAY,OACZ,WAAY,KATd,wBAYI,QAAS,aACT,MhDinB0C,KgDhnB1C,OhDgnB0C,KgD/mB1C,OAAQ,IACR,YAAa,OACb,OAAQ,QAMR,iBAAkB,YAClB,OAAQ,IAAI,MhDymB8B,KgDxmB1C,chDqmB0C,KkD7wB9C,eAHA,anCII,wBbKiB,IgDHrB,gBAHA,enCOI,2BbDiB,IgDHrB,gBAGA,cnCQI,0BbRiB,IgDArB,cATA,anCkBI,uBbTiB,I8CyIrB,6BA6BI,MhDkmB0C,KgDjmB1C,OhDimB0C,KgDhmB1C,OAAQ,EACR,iBhDgmB0C,KgDvlB9C,kBACE,SAAU,SACV,MAAS,IACT,OAAQ,KACR,KAAQ,IACR,QAAS,GACT,YAAa,KACb,eAAgB,KAPlB,uBCjJA,WEpDE,YAAa,KCJf,gBAAkB,eAAgB,mBAClC,WAAa,eAAgB,cAC7B,cAAgB,eAAgB,iBAChC,cAAgB,eAAgB,iBAChC,mBAAqB,eAAgB,sBACrC,gBAAkB,eAAgB,mBCDlC,UACE,iBnDOmB,QoDTnB,YACE,iBpDJQ,kBoDMV,mBAAA,mBAEI,iBAAkB,kBALtB,YACE,iBpDFS,kBoDIX,mBAAA,mBAEI,iBAAkB,kBALtB,SACE,iBtDyBwB,kBsDvB1B,gBAAA,gBAEI,iBAAkB,kBALtB,YACE,iBpDAU,kBoDEZ,mBAAA,mBAEI,iBAAkB,kBALtB,WACE,iBpDCO,kBoDCT,kBAAA,kBAEI,iBAAkB,kBALtB,YACE,iBpDIe,kBoDFjB,mBAAA,mBAEI,iBAAkB,kBJGxB,SnCPI,cbmBiB,IgDIrB,gBACE,cAAe,IK5BjB,iBzCEI,QAAS,GACT,QAAS,MACT,MAAO,K0CAX,SACE,QAAS,gBAEX,gBACE,QAAS,uBAEX,UACE,QAAS,iBCKT,gBALA,cAiBF,qBAVM,QAAS,eCVT,eAAE,MAAO,GACT,cAAE,MAAO,EACT,mBAAE,MAAO,EAKT,mBAAE,YAAa,WACf,sBAAE,YAAa,OACf,sBAAE,YAAa,SAKf,aAAE,WAAY,WACd,gBAAE,WAAY,OACd,gBAAE,WAAY,SAKd,oBAAE,gBAAiB,WACnB,sBAAE,gBAAiB,OACnB,qBAAE,gBAAiB,SACnB,sBAAE,gBAAiB,aACnB,uBAAE,gBAAiB,cC/BrB,eCDF,MAAO,eDIL,gBCDF,MAAO,gBDIL,eACE,MAAO,e3CoCT,yBgCoLF,6BAAA,6BAGI,MhDojBwC,KgDnjBxC,OhDmjBwC,KgDljBxC,WAAc,MACd,UhDijBwC,KgDvjB5C,6BASI,YAAe,MATnB,6BAYI,aAAgB,MAKpB,kBACE,MAAS,IACT,KAAQ,IACR,eAAgB,KAIlB,qBACE,OAAQ,KUlPN,eAAE,MAAO,GACT,cAAE,MAAO,EACT,mBAAE,MAAO,EAKT,mBAAE,YAAa,WACf,sBAAE,YAAa,OACf,sBAAE,YAAa,SAKf,aAAE,WAAY,WACd,gBAAE,WAAY,OACd,gBAAE,WAAY,SAKd,oBAAE,gBAAiB,WACnB,sBAAE,gBAAiB,OACnB,qBAAE,gBAAiB,SACnB,sBAAE,gBAAiB,aACnB,uBAAE,gBAAiB,cC/BrB,eCDF,MAAO,eDIL,gBCDF,MAAO,gBDIL,eACE,MAAO,gBELb,SCCE,SAAU,SACV,MAAO,IACP,OAAQ,IACR,QAAS,EACT,OAAQ,KACR,SAAU,OACV,KAAM,cACN,OAAQ,ECON,MAKA,MACE,c/DmCa,Y+DvCf,MAGA,MAEE,a/DkCa,Y+D1Cf,MAUA,MACE,Y/DgCa,Y+DzCf,MAQA,MAEE,e/D+Ba,Y6DrDnB,0BAAA,yBCgBI,SAAU,OACV,MAAO,KACP,OAAQ,KACR,OAAQ,EACR,SAAU,QACV,KAAM,KCXN,MAUA,MACE,W/DgCa,Y+DzCf,MAQA,MAEE,c/D+Ba,Y+D3DnB,OAAS,MAAO,eAChB,OAAS,OAAQ,eAIjB,SACE,aAAc,eACd,YAAc,eAUZ,MAKA,MACE,a/DmCa,Y+DvCf,MAGA,MAEE,Y/DkCa,Y+D3Cf,KAAE,O/D4Ca,Y+D1Cf,MAKA,MACE,a/D8BK,e+DlCP,MAGA,MAEE,Y/D6BK,e+DrCP,MAUA,MACE,W/D0BK,e+DnCP,MAQA,MAEE,c/DyBK,e+DtCP,KAAE,O/DsCK,e+DpCP,MAKA,MACE,a/D2Cc,iB+D/ChB,MAGA,MAEE,Y/D0Cc,iB+DlDhB,MAUA,MACE,W/DwCc,iB+DjDhB,MAQA,MAEE,c/DuCc,iB+DpDhB,KAAE,O/DoDc,iB+DlDhB,MAKA,MACE,a/D+Cc,e+DnDhB,MAGA,MAEE,Y/D8Cc,e+DtDhB,MAUA,MACE,W/D4Cc,e+DrDhB,MAQA,MAEE,c/D2Cc,e+DxDhB,KAAE,O/DwDc,e+DxDhB,KAAE,Q/D4Ca,Y+D1Cf,MAKA,MACE,c/D8BK,e+DlCP,MAGA,MAEE,a/D6BK,e+DrCP,MAUA,MACE,Y/D0BK,e+DnCP,MAQA,MAEE,e/DyBK,e+DtCP,KAAE,Q/DsCK,e+DpCP,MAKA,MACE,c/D2Cc,iB+D/ChB,MAGA,MAEE,a/D0Cc,iB+DlDhB,MAUA,MACE,Y/DwCc,iB+DjDhB,MAQA,MAEE,e/DuCc,iB+DpDhB,KAAE,Q/DoDc,iB+DlDhB,MAKA,MACE,c/D+Cc,e+DnDhB,MAGA,MAEE,a/D8Cc,e+DtDhB,MAUA,MACE,Y/D4Cc,e+DrDhB,MAQA,MAEE,e/D2Cc,e+DxDhB,KAAE,Q/DwDc,e+DpCpB,SACE,SAAU,MACV,IAAK,EACL,MAAO,EACP,KAAM,EACN,Q/DmayB,KiDvc3B,cAAuB,WAAY,kBACnC,aAAuB,YAAa,iBACpC,eeJE,SAAU,OACV,cAAe,SACf,YAAa,OfQX,cAAE,WAAY,eACd,eAAE,WAAY,gBACd,gBAAE,WAAY,iBAMlB,gBAAuB,eAAgB,oBACvC,gBAAuB,eAAgB,oBACvC,iBAAuB,eAAgB,qBAIvC,oBAAuB,YAAa,IACpC,kBAAuB,YAAa,IACpC,aAAuB,WAAY,OAInC,YACE,MAAO,egBhCP,YACE,M/DMc,kB+DJhB,mBAAA,mBAEI,MAAO,kBALX,cACE,M/DJQ,kB+DMV,qBAAA,qBAEI,MAAO,kBALX,cACE,M/DFS,kB+DIX,qBAAA,qBAEI,MAAO,kBALX,WACE,MjEyBwB,kBiEvB1B,kBAAA,kBAEI,MAAO,kBALX,cACE,M/DAU,kB+DEZ,qBAAA,qBAEI,MAAO,kBALX,aACE,M/DCO,kB+DCT,oBAAA,oBAEI,MAAO,kBALX,gBACE,M/DIe,kB+DFjB,uBAAA,uBAEI,MAAO,kBhBgDb,WEtDE,KAAM,EAAA,EAAM,EACZ,MAAO,YAEP,iBAAkB,YAClB,OAAQ,ER0DV,UAdA,oBAgBE,cAAe,MzC1CG,IACA,QuDrBpB,WACE,WAAY,iBzCqDV,yByC1CF,gBAEI,QAAS,gBzC2BX,yBiC/BA,cAAE,WAAY,eACd,eAAE,WAAY,gBACd,gBAAE,WAAY,iBQLhB,cAEI,QAAS,gBzC6CX,yByC1CF,gBAEI,QAAS,gBzC2BX,yB0CrCE,eAAE,MAAO,GACT,cAAE,MAAO,EACT,mBAAE,MAAO,EAKT,mBAAE,YAAa,WACf,sBAAE,YAAa,OACf,sBAAE,YAAa,SAKf,aAAE,WAAY,WACd,gBAAE,WAAY,OACd,gBAAE,WAAY,SAKd,oBAAE,gBAAiB,WACnB,sBAAE,gBAAiB,OACnB,qBAAE,gBAAiB,SACnB,sBAAE,gBAAiB,aACnB,uBAAE,gBAAiB,cC/BrB,eCDF,MAAO,eDIL,gBCDF,MAAO,gBDIL,eACE,MAAO,eVKT,cAAE,WAAY,eACd,eAAE,WAAY,gBACd,gBAAE,WAAY,iBQLhB,cAEI,QAAS,gBzC6CX,yByC1CF,gBAEI,QAAS,gBzC2BX,yB0CrCE,eAAE,MAAO,GACT,cAAE,MAAO,EACT,mBAAE,MAAO,EAKT,mBAAE,YAAa,WACf,sBAAE,YAAa,OACf,sBAAE,YAAa,SAKf,aAAE,WAAY,WACd,gBAAE,WAAY,OACd,gBAAE,WAAY,SAKd,oBAAE,gBAAiB,WACnB,sBAAE,gBAAiB,OACnB,qBAAE,gBAAiB,SACnB,sBAAE,gBAAiB,aACnB,uBAAE,gBAAiB,cC/BrB,eCDF,MAAO,eDIL,gBCDF,MAAO,gBDIL,eACE,MAAO,eVKT,cAAE,WAAY,eACd,eAAE,WAAY,gBACd,gBAAE,WAAY,iBQLhB,cAEI,QAAS,gBzC6CX,0ByC1CF,gBAEI,QAAS,gBzC2BX,0B0CrCE,eAAE,MAAO,GACT,cAAE,MAAO,EACT,mBAAE,MAAO,EAKT,mBAAE,YAAa,WACf,sBAAE,YAAa,OACf,sBAAE,YAAa,SAKf,aAAE,WAAY,WACd,gBAAE,WAAY,OACd,gBAAE,WAAY,SAKd,oBAAE,gBAAiB,WACnB,sBAAE,gBAAiB,OACnB,qBAAE,gBAAiB,SACnB,sBAAE,gBAAiB,aACnB,uBAAE,gBAAiB,cC/BrB,eCDF,MAAO,eDIL,gBCDF,MAAO,gBDIL,eACE,MAAO,eVKT,cAAE,WAAY,eACd,eAAE,WAAY,gBACd,gBAAE,WAAY,iBQLhB,cAEI,QAAS,gBAkBb,aAHF,qBAII,QAAS,iBAGb,sBACE,QAAS,eAET,aAHF,sBAII,QAAS,kBAGb,4BACE,QAAS,eAQT,aATF,4BAII,QAAS,uBAIb,cAEI,QAAS,gBd7Cb,UACE,SAAU,SACV,OzC0DmB,KyC5DrB,oBAKI,MzCHa,QyCIb,OzCsDiB,KyCrDjB,YzCqDiB,KyCpDjB,QAAS,EzCME,KyCLX,UzCkDoB,KyCjDpB,YAAa,IA2EjB,aArFA,2BA4MM,MzClLuB,QyC2D7B,aA8BA,gBAuFM,UzClLsB,KyCxB5B,kCAiBM,QAAS,GACT,QAAS,MACT,SAAU,SACV,KAAM,KACN,MAAO,KACP,OAAQ,EACR,OzCsCoB,IyCrCpB,cAAe,IACf,iBzC/BQ,QyCMd,iCAgCM,cAAe,EAhCrB,+CAoCM,MAAO,KAOb,oBAGI,OAAQ,KAHZ,qBAQI,iBAAkB,KAMtB,UACE,iBzCrDmB,QyCoDrB,oBAKI,QAAS,aACT,MAAO,KAIX,0CAEI,aAAc,EACd,YAAa,EACb,YAAa,IACb,cAAe,WASnB,YACE,WzCpEa,KyCuEf,aAEE,YzC9D4B,IyCgE5B,WzCrBkC,KyCsBlC,cAAe,WAUjB,6DAEI,iB3C2mB4B,K2C9lBhC,OACE,iBAAkB,YADpB,aAAA,aAAA,aAMI,iBAAkB,KANtB,iCAYI,WAAY,EAZhB,sBAsBI,gBAAiB,SACjB,eAAgB,EAChB,czC3HiB,IyCmGrB,oDA4BQ,cAAe,SACf,SAAU,OACV,YAAa,OACb,UzC7D+B,MyC8BvC,yBAAA,yBAqCM,YAAa,EACb,WAAY,EACZ,czCzIc,IyCyIoB,MzC1EF,KyC2EhC,azC1Ic,IyC0ImB,MzC3ED,KyCmCtC,yCA6CM,cAAe,EA7CrB,sCAAA,sCAkDM,aAAc,EAlDpB,wDAsDM,uBAAwB,IAtD9B,uDA0DM,wBAAyB,IA1D/B,uDA8DM,0BAA2B,IA9DjC,sDAkEM,2BAA4B,IAlElC,qDAAA,qDAyEM,aAAc,EACd,cAAe,EA1ErB,sBAgFI,iBzC9LiB,QyC8GrB,yBAAA,yBAAA,4BAuFM,UzClLsB,KyCmLtB,YzClLwB,IyCmLxB,MzClLuB,QyCmLvB,iBAAkB,YA1FxB,0BAiGI,SAAU,SACV,IAAK,EACL,KAAM,EACN,MAAO,EACP,OAAQ,EACR,QAAS,KAET,eAAgB,OAChB,YAAa,QAzGjB,gCA4GM,QAAS,KACT,eAAgB,OAChB,YAAa,QACb,SAAU,SA/GhB,6BAAA,gCAAA,6BAAA,gCAuHM,YAAa,EAvHnB,gCA2HM,WAAY,OACZ,QAAS,aA5Hf,mCAAA,mCAAA,mCAkIM,QAAS,KACT,eAAgB,IAChB,UAAW,OApIjB,mCAAA,mCA0IM,WAAY,OACZ,cAAe,SACf,QAAS,aACT,YAAa,OA7InB,oCAAA,6BAAA,6BANE,UAAW,KACX,MAAW,KACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,KACX,MAAW,KACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,MACX,MAAW,MACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,MACX,MAAW,MACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,MACX,MAAW,MACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,MACX,MAAW,MACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,MACX,MAAW,MACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,MACX,MAAW,MACX,UAsJe,EArJf,YAAa,EAGf,oCANE,UAAW,MACX,MAAW,MACX,UAsJe,EArJf,YAAa,EAGf,qCANE,UAAW,MACX,MAAW,MACX,UAsJe,GArJf,YAAa,EAGf,qCANE,UAAW,MACX,MAAW,MACX,UAsJe,GArJf,YAAa,EAGf,qCANE,UAAW,MACX,MAAW,MACX,UAsJe,GArJf,YAAa,EAGf,qCANE,UAAW,MACX,MAAW,MACX,UAsJe,GArJf,YAAa,EAGf,qCANE,UAAW,MACX,MAAW,MACX,UAsJe,GArJf,YAAa,EAGf,qCANE,UAAW,MACX,MAAW,MACX,UAsJe,GArJf,YAAa,EAGf,qCANE,UAAW,MACX,MAAW,MACX,UAsJe,GArJf,YAAa,EAGf,0CAiKM,QAAS,GACT,QAAS,MACT,WAAY,OACZ,WAAY,OApKlB,yCAyKM,OAAQ,EAzKd,+CAAA,+CAAA,+CA8KQ,YAAa,MAAM,IzC/QP,QyCgRZ,aAAc,MAAM,IzChRR,QyCiGpB,+CAmLQ,WAAY,MAAM,IzCpRN,QyCqRZ,uBzCvRa,IyCwRb,wBzCxRa,IyCmGrB,+CAAA,+CA0LQ,cAAe,MAAM,IzC3RT,QyC4RZ,0BzC9Ra,IyC+Rb,2BzC/Ra,IyCmGrB,qDAiMQ,cAAe,EACf,0BAA2B,EAC3B,2BAA4B,EAnMpC,uDA6MM,YzC7OsB,MyC8OtB,azC9OsB,MyCgC5B,sDAkNM,MAAO,KACP,QAAS,EAAA,IAnNf,0DAuNM,MAAO,IAvNb,0DA0NM,MAAO,OA1Nb,0DA6NM,MAAO,IA7Nb,0DAgOM,MAAO,IAhOb,2CAoOM,OAAQ,KACR,SAAU,OArOhB,wCAyOM,MzC1VW,QyC2VX,UAAW,KA1OjB,2CA8OM,SAAU,SACV,IAAK,KACL,MzCjWW,QyCkWX,UAAW,KAjPjB,8DAsPM,SAAU,SACV,IAAK,IACL,OAAQ,KACR,MzC1WW,QyC+WjB,8BACE,SAAU,SACV,WAAY,OAMd,sBACE,SAAU,SACV,QAAS,IACT,MzClYY,QyCmYZ,MAAO,KAGT,OACE,OAAQ,QADV,8BAII,iBAAkB,KAJtB,qBAQI,oBAAqB,MAIzB,kBAEI,YACA,OAAQ,KAIZ,mBACE,OzChXgB,KyCiXhB,YzCjXgB,KyCsXlB,KACE,UAAW,MACX,WzCxXgB,KyCsXlB,sBAKI,QAAS,EACT,OzC5Xc,KyC6Xd,UzC7Xc,KyC8Xd,MzC9Xc,KyC+Xd,SAAU,SATd,wCAYM,OzClXiB,KyCmXjB,SAAU,SACV,IAAM,IACN,KAAO,IAfb,oDAmBM,KzCxYmB,KyCqXzB,sDAuBM,KzCzYqB,QyCkX3B,mBA6BI,oBAAqB,OAAA,WAAA,MA7BzB,yBAAA,yBAAA,yBAiCI,iBAAkB,KAjCtB,yCAAA,yCAAA,yCAmCM,WAAY,EAAE,IAAI,IAAI,eAnC5B,gBAyCI,WzCpa2B,4NAAA,MyCoae,EAAK,OAAG,UAAO,KACzD,cAAe,KA1CnB,mBA6CM,iBzCvauB,4NyCgb7B,mBACE,OzCtbyB,KyCubzB,YAAa,EACb,eAAgB,EAKlB,iBAKE,SAAU,SALZ,mCAQI,MAPW,KAQX,OARW,KASX,SAAU,SACV,QAAS,EACT,IAAK,uBACL,KzClec,QyCqdlB,wDAAA,0DAyCM,MAvCY,KAwCZ,OAxCY,KAFlB,8BAiBI,aAAc,uBAjBlB,iCA2BM,aAAc,uBA3BpB,gDAgCI,KA7Be,IAHnB,6BAoCI,cAAe,uBApCnB,gCA8CM,cAAe,uBA9CrB,+CAmDI,MAhDe,IAHnB,+CAuDI,WAAY,KAAA,YAAA,KAvDhB,sDAAA,qDA2DM,KzClhBa,QyCmhBb,OAAQ,QAOd,eACE,MAAO,KACP,OzClgByB,KyCsgB3B,iCACE,OAAQ","file":"bootstrap.css","sourcesContent":["/*! normalize.css v4.2.0 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Change the default font family in all browsers (opinionated).\n// 2. Correct the line height in all browsers.\n// 3. Prevent adjustments of font size after orientation changes in IE and iOS.\n//\n\nhtml {\n font-family: sans-serif; // 1\n line-height: 1.15; // 2\n -ms-text-size-adjust: 100%; // 3\n -webkit-text-size-adjust: 100%; // 3\n}\n\n//\n// Remove the margin in all browsers (opinionated).\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Add the correct display in IE 9-.\n// 1. Add the correct display in Edge, IE, and Firefox.\n// 2. Add the correct display in IE.\n//\n\narticle,\naside,\ndetails, // 1\nfigcaption,\nfigure,\nfooter,\nheader,\nmain, // 2\nmenu,\nnav,\nsection,\nsummary { // 1\n display: block;\n}\n\n//\n// Add the correct display in IE 9-.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n}\n\n//\n// Add the correct display in iOS 4-7.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Add the correct vertical alignment in Chrome, Firefox, and Opera.\n//\n\nprogress {\n vertical-align: baseline;\n}\n\n//\n// Add the correct display in IE 10-.\n// 1. Add the correct display in IE.\n//\n\ntemplate, // 1\n[hidden] {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// 1. Remove the gray background on active links in IE 10.\n// 2. Remove gaps in links underline in iOS 8+ and Safari 8+.\n//\n\na {\n background-color: transparent; // 1\n -webkit-text-decoration-skip: objects; // 2\n}\n\n//\n// Remove the outline on focused links when they are also active or hovered\n// in all browsers (opinionated).\n//\n\na:active,\na:hover {\n outline-width: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// 1. Remove the bottom border in Firefox 39-.\n// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n//\n\nabbr[title] {\n border-bottom: none; // 1\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n}\n\n//\n// Prevent the duplicate application of `bolder` by the next rule in Safari 6.\n//\n\nb,\nstrong {\n font-weight: inherit;\n}\n\n//\n// Add the correct font weight in Chrome, Edge, and Safari.\n//\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n//\n// Add the correct font style in Android 4.3-.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Correct the font size and margin on `h1` elements within `section` and\n// `article` contexts in Chrome, Firefox, and Safari.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Add the correct background and color in IE 9-.\n//\n\nmark {\n background-color: #ff0;\n color: #000;\n}\n\n//\n// Add the correct font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove the border on images inside links in IE 10-.\n//\n\nimg {\n border-style: none;\n}\n\n//\n// Hide the overflow in IE.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// 1. Correct the inheritance and scaling of font size in all browsers.\n// 2. Correct the odd `em` font sizing in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace; // 1\n font-size: 1em; // 2\n}\n\n//\n// Add the correct margin in IE 8.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// 1. Add the correct box sizing in Firefox.\n// 2. Show the overflow in Edge and IE.\n//\n\nhr {\n box-sizing: content-box; // 1\n height: 0; // 1\n overflow: visible; // 2\n}\n\n// Forms\n// ==========================================================================\n\n//\n// 1. Change font properties to `inherit` in all browsers (opinionated).\n// 2. Remove the margin in Firefox and Safari.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font: inherit; // 1\n margin: 0; // 2\n}\n\n//\n// Restore the font weight unset by the previous rule.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n//\n// Show the overflow in IE.\n// 1. Show the overflow in Edge.\n//\n\nbutton,\ninput { // 1\n overflow: visible;\n}\n\n//\n// Remove the inheritance of text transform in Edge, Firefox, and IE.\n// 1. Remove the inheritance of text transform in Firefox.\n//\n\nbutton,\nselect { // 1\n text-transform: none;\n}\n\n//\n// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`\n// controls in Android 4.\n// 2. Correct the inability to style clickable types in iOS and Safari.\n//\n\nbutton,\nhtml [type=\"button\"], // 1\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button; // 2\n}\n\n//\n// Remove the inner border and padding in Firefox.\n//\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n//\n// Restore the focus styles unset by the previous rule.\n//\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n//\n// Change the border, margin, and padding in all browsers (opinionated).\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct the text wrapping in Edge and IE.\n// 2. Correct the color inheritance from `fieldset` elements in IE.\n// 3. Remove the padding so developers are not caught out when they zero out\n// `fieldset` elements in all browsers.\n//\n\nlegend {\n box-sizing: border-box; // 1\n color: inherit; // 2\n display: table; // 1\n max-width: 100%; // 1\n padding: 0; // 3\n white-space: normal; // 1\n}\n\n//\n// Remove the default vertical scrollbar in IE.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// 1. Add the correct box sizing in IE 10-.\n// 2. Remove the padding in IE 10-.\n//\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Correct the cursor style of increment and decrement buttons in Chrome.\n//\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Correct the odd appearance in Chrome and Safari.\n// 2. Correct the outline style in Safari.\n//\n\n[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n outline-offset: -2px; // 2\n}\n\n//\n// Remove the inner padding and cancel buttons in Chrome and Safari on OS X.\n//\n\n[type=\"search\"]::-webkit-search-cancel-button,\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Correct the text style of placeholders in Chrome, Edge, and Safari.\n//\n\n::-webkit-input-placeholder {\n color: inherit;\n opacity: 0.54;\n}\n\n//\n// 1. Correct the inability to style clickable types in iOS and Safari.\n// 2. Change font properties to `inherit` in Safari.\n//\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; // 1\n font: inherit; // 2\n}\n","// scss-lint:disable QualifyingElement, DuplicateProperty\n\n// Reboot\n//\n// Global resets to common HTML elements and more for easier usage by Bootstrap.\n// Adds additional rules on top of Normalize.css, including several overrides.\n\n\n// Reset the box-sizing\n//\n// Change from `box-sizing: content-box` to `border-box` so that when you add\n// `padding` or `border`s to an element, the overall declared `width` does not\n// change. For example, `width: 100px;` will always be `100px` despite the\n// `border: 10px solid red;` and `padding: 20px;`.\n//\n// Heads up! This reset may cause conflicts with some third-party widgets. For\n// recommendations on resolving such conflicts, see\n// https://getbootstrap.com/getting-started/#third-box-sizing.\n//\n// Credit: https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/\n\nhtml {\n box-sizing: border-box;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n\n// Make viewport responsive\n//\n// @viewport is needed because IE 10+ doesn't honor in\n// some cases. See https://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/.\n// Eventually @viewport will replace .\n//\n// However, `device-width` is broken on IE 10 on Windows (Phone) 8,\n// (see https://timkadlec.com/2013/01/windows-phone-8-and-device-width/ and https://github.com/twbs/bootstrap/issues/10497)\n// and the fix for that involves a snippet of JavaScript to sniff the user agent\n// and apply some conditional CSS.\n//\n// See https://getbootstrap.com/getting-started/#support-ie10-width for the relevant hack.\n//\n// Wrap `@viewport` with `@at-root` for when folks do a nested import (e.g.,\n// `.class-name { @import \"bootstrap\"; }`).\n@at-root {\n @-ms-viewport { width: device-width; }\n}\n\n\n//\n// Reset HTML, body, and more\n//\n\nhtml {\n // Sets a specific default `font-size` for user with `rem` type scales.\n font-size: $font-size-root;\n // As a side-effect of setting the @viewport above,\n // IE11 & Edge make the scrollbar overlap the content and automatically hide itself when not in use.\n // Unfortunately, the auto-showing of the scrollbar is sometimes too sensitive,\n // thus making it hard to click on stuff near the right edge of the page.\n // So we add this style to force IE11 & Edge to use a \"normal\", non-overlapping, non-auto-hiding scrollbar.\n // See https://github.com/twbs/bootstrap/issues/18543\n -ms-overflow-style: scrollbar;\n // Changes the default tap highlight to be completely transparent in iOS.\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n // Make the `body` use the `font-size-root`\n font-family: $font-family-base;\n font-size: $font-size-base;\n line-height: $line-height-base;\n // Go easy on the eyes and use something other than `#000` for text\n color: $body-color;\n // By default, `` has no `background-color` so we set one as a best practice.\n background-color: $body-bg;\n}\n\n// Suppress the focus outline on elements that cannot be accessed via keyboard.\n// This prevents an unwanted focus outline from appearing around elements that\n// might still respond to pointer events.\n//\n// Credit: https://github.com/suitcss/base\n[tabindex=\"-1\"]:focus {\n outline: none !important;\n}\n\n\n//\n// Typography\n//\n\n// Remove top margins from headings\n//\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\nh1, h2, h3, h4, h5, h6 {\n margin-top: 0;\n margin-bottom: .5rem;\n}\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\np {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted $abbr-border-color;\n}\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // Undo browser default\n}\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n//\n// Links\n//\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n\n @include hover-focus {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n\n &:focus {\n @include tab-focus();\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href)\n// which have not been made explicitly keyboard-focusable (without tabindex).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([tabindex]) {\n color: inherit;\n text-decoration: none;\n\n @include hover-focus {\n color: inherit;\n text-decoration: none;\n }\n\n &:focus {\n outline: none;\n }\n}\n\n\n//\n// Code\n//\n\npre {\n // Remove browser default top margin\n margin-top: 0;\n // Reset browser default of `1em` to use `rem`s\n margin-bottom: 1rem;\n // Normalize v4 removed this property, causing `

` content to break out of wrapping code snippets\n  overflow: auto;\n}\n\n\n//\n// Figures\n//\n\nfigure {\n  // Normalize adds `margin` to `figure`s as browsers apply it inconsistently.\n  // We reset that to create a better flow in-page.\n  margin: 0 0 1rem;\n}\n\n\n//\n// Images\n//\n\nimg {\n  // By default, ``s are `inline-block`. This assumes that, and vertically\n  // centers them. This won't apply should you reset them to `block` level.\n  vertical-align: middle;\n  // Note: ``s are deliberately not made responsive by default.\n  // For the rationale behind this, see the comments on the `.img-fluid` class.\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n  cursor: pointer;\n}\n\n\n// Avoid 300ms click delay on touch devices that support the `touch-action` CSS property.\n//\n// In particular, unlike most other browsers, IE11+Edge on Windows 10 on touch devices and IE Mobile 10-11\n// DON'T remove the click delay when `` is present.\n// However, they DO support removing the click delay via `touch-action: manipulation`.\n// See:\n// * https://v4-alpha.getbootstrap.com/content/reboot/#click-delay-optimization-for-touch\n// * http://caniuse.com/#feat=css-touch-action\n// * https://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay\n\na,\narea,\nbutton,\n[role=\"button\"],\ninput,\nlabel,\nselect,\nsummary,\ntextarea {\n  touch-action: manipulation;\n}\n\n\n//\n// Tables\n//\n\ntable {\n  // No longer part of Normalize since v4\n  border-collapse: collapse;\n  // Reset for nesting within parents with `background-color`.\n  background-color: $table-bg;\n}\n\ncaption {\n  padding-top: $table-cell-padding;\n  padding-bottom: $table-cell-padding;\n  color: $text-muted;\n  text-align: left;\n  caption-side: bottom;\n}\n\nth {\n  // Centered by default, but left-align-ed to match the `td`s below.\n  text-align: left;\n}\n\n\n//\n// Forms\n//\n\nlabel {\n  // Allow labels to use `margin` for spacing.\n  display: inline-block;\n  margin-bottom: .5rem;\n}\n\n// Work around a Firefox/IE bug where the transparent `button` background\n// results in a loss of the default `button` focus styles.\n//\n// Credit: https://github.com/suitcss/base/\nbutton:focus {\n  outline: 1px dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  // Normalize includes `font: inherit;`, so `font-family`. `font-size`, etc are\n  // properly inherited. However, `line-height` isn't inherited there.\n  line-height: inherit;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  // Apply a disabled cursor for radios and checkboxes.\n  //\n  // Note: Neither radios nor checkboxes can be readonly.\n  &:disabled {\n    cursor: $cursor-disabled;\n  }\n}\n\n\ninput[type=\"date\"],\ninput[type=\"time\"],\ninput[type=\"datetime-local\"],\ninput[type=\"month\"] {\n  // Remove the default appearance of temporal inputs to avoid a Mobile Safari\n  // bug where setting a custom line-height prevents text from being vertically\n  // centered within the input.\n  //\n  // Bug report: https://github.com/twbs/bootstrap/issues/11266\n  -webkit-appearance: listbox;\n}\n\ntextarea {\n  // Textareas should really only resize vertically so they don't break their (horizontal) containers.\n  resize: vertical;\n}\n\nfieldset {\n  // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n  // so we reset that to ensure it behaves more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359.\n  min-width: 0;\n  // Reset the default outline behavior of fieldsets so they don't affect page layout.\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n\nlegend {\n  // Reset the entire legend element to match the `fieldset`\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: .5rem;\n  font-size: 1.5rem;\n  line-height: inherit;\n}\n\ninput[type=\"search\"] {\n  // This overrides the extra rounded corners on search inputs in iOS so that our\n  // `.form-control` class can properly style them. Note that this cannot simply\n  // be added to `.form-control` as it's not specific enough. For details, see\n  // https://github.com/twbs/bootstrap/issues/11586.\n  -webkit-appearance: none;\n}\n\n// todo: needed?\noutput {\n  display: inline-block;\n//  font-size: $font-size-base;\n//  line-height: $line-height;\n//  color: $input-color;\n}\n\n// Always hide an element with the `hidden` HTML attribute (from PureCSS).\n[hidden] {\n  display: none !important;\n}\n","// scss-lint:disable PropertyCount\n\n// Embedded icons from Open Iconic.\n// Released under MIT and copyright 2014 Waybury.\n// https://useiconic.com/open\n\n\n// Checkboxes and radios\n//\n// Base class takes care of all the key behavioral aspects.\n\n.custom-control {\n  position: relative;\n  display: inline-block;\n  padding-left: $custom-control-gutter;\n  cursor: pointer;\n\n  + .custom-control {\n    margin-left: $custom-control-spacer-x;\n  }\n}\n\n.custom-control-input {\n  position: absolute;\n  z-index: -1; // Put the input behind the label so it doesn't overlay text\n  opacity: 0;\n\n  &:checked ~ .custom-control-indicator {\n    color: $custom-control-checked-indicator-color;\n    background-color: $custom-control-checked-indicator-bg;\n    @include box-shadow($custom-control-checked-indicator-box-shadow);\n  }\n\n  &:focus ~ .custom-control-indicator {\n    // the mixin is not used here to make sure there is feedback\n    box-shadow: $custom-control-focus-indicator-box-shadow;\n  }\n\n  &:active ~ .custom-control-indicator {\n    color: $custom-control-active-indicator-color;\n    background-color: $custom-control-active-indicator-bg;\n    @include box-shadow($custom-control-active-indicator-box-shadow);\n  }\n\n  &:disabled {\n    ~ .custom-control-indicator {\n      cursor: $custom-control-disabled-cursor;\n      background-color: $custom-control-disabled-indicator-bg;\n    }\n\n    ~ .custom-control-description {\n      color: $custom-control-disabled-description-color;\n      cursor: $custom-control-disabled-cursor;\n    }\n  }\n}\n\n// Custom indicator\n//\n// Generates a shadow element to create our makeshift checkbox/radio background.\n\n.custom-control-indicator {\n  position: absolute;\n  top: .25rem;\n  left: 0;\n  display: block;\n  width: $custom-control-indicator-size;\n  height: $custom-control-indicator-size;\n  pointer-events: none;\n  user-select: none;\n  background-color: $custom-control-indicator-bg;\n  background-repeat: no-repeat;\n  background-position: center center;\n  background-size: $custom-control-indicator-bg-size;\n  @include box-shadow($custom-control-indicator-box-shadow);\n}\n\n// Checkboxes\n//\n// Tweak just a few things for checkboxes.\n\n.custom-checkbox {\n  .custom-control-indicator {\n    @include border-radius($custom-checkbox-radius);\n  }\n\n  .custom-control-input:checked ~ .custom-control-indicator {\n    background-image: $custom-checkbox-checked-icon;\n  }\n\n  .custom-control-input:indeterminate ~ .custom-control-indicator {\n    background-color: $custom-checkbox-indeterminate-bg;\n    background-image: $custom-checkbox-indeterminate-icon;\n    @include box-shadow($custom-checkbox-indeterminate-box-shadow);\n  }\n}\n\n// Radios\n//\n// Tweak just a few things for radios.\n\n.custom-radio {\n  .custom-control-indicator {\n    border-radius: $custom-radio-radius;\n  }\n\n  .custom-control-input:checked ~ .custom-control-indicator {\n    background-image: $custom-radio-checked-icon;\n  }\n}\n\n\n// Layout options\n//\n// By default radios and checkboxes are `inline-block` with no additional spacing\n// set. Use these optional classes to tweak the layout.\n\n.custom-controls-stacked {\n  .custom-control {\n    float: left;\n    clear: left;\n\n    + .custom-control {\n      margin-left: 0;\n    }\n  }\n}\n\n\n// Select\n//\n// Replaces the browser default select with a custom one, mostly pulled from\n// http://primercss.io.\n//\n// Includes IE9-specific hacks (noted by ` \\9`).\n\n.custom-select {\n  display: inline-block;\n  max-width: 100%;\n  $select-border-width: ($border-width * 2);\n  height: calc(#{$input-height} - #{$select-border-width});\n  padding: $custom-select-padding-y ($custom-select-padding-x + $custom-select-indicator-padding) $custom-select-padding-y $custom-select-padding-x;\n  padding-right: $custom-select-padding-x \\9;\n  color: $custom-select-color;\n  vertical-align: middle;\n  background: $custom-select-bg $custom-select-indicator no-repeat right $custom-select-padding-x center;\n  background-image: none \\9;\n  background-size: $custom-select-bg-size;\n  border: $custom-select-border-width solid $custom-select-border-color;\n  @include border-radius($custom-select-border-radius);\n  // Use vendor prefixes as `appearance` isn't part of the CSS spec.\n  -moz-appearance: none;\n  -webkit-appearance: none;\n\n  &:focus {\n    border-color: $custom-select-focus-border-color;\n    outline: none;\n    @include box-shadow($custom-select-focus-box-shadow);\n\n    &::-ms-value {\n      // For visual consistency with other platforms/browsers,\n      // supress the default white text on blue background highlight given to\n      // the selected option text when the (still closed) s in some browsers, due to the limited stylability of ``s in IE10+.\n  &::-ms-expand {\n    background-color: transparent;\n    border: 0;\n  }\n\n  // Customize the `:focus` state to imitate native WebKit styles.\n  @include form-control-focus();\n\n  // Placeholder\n  &::placeholder {\n    color: $input-color-placeholder;\n    // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.\n    opacity: 1;\n  }\n\n  // Disabled and read-only inputs\n  //\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\n  // don't honor that edge case; we style them as disabled anyway.\n  &:disabled,\n  &[readonly] {\n    background-color: $input-bg-disabled;\n    // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.\n    opacity: 1;\n  }\n\n  &:disabled {\n    cursor: $cursor-disabled;\n  }\n}\n\nselect.form-control {\n  &:not([size]):not([multiple]) {\n    $select-border-width: ($border-width * 2);\n    height: calc(#{$input-height} - #{$select-border-width});\n  }\n\n  &:focus::-ms-value {\n    // Suppress the nested default white text on blue background highlight given to\n    // the selected option text when the (still closed) `\n// element gets special love because it's special, and that's a fact!\n\n@mixin input-size($parent, $input-height, $padding-y, $padding-x, $font-size, $line-height, $border-radius) {\n  #{$parent} {\n    height: $input-height;\n    padding: $padding-y $padding-x;\n    font-size: $font-size;\n    line-height: $line-height;\n    @include border-radius($border-radius);\n  }\n\n  select#{$parent} {\n    height: $input-height;\n    line-height: $input-height;\n  }\n\n  textarea#{$parent},\n  select[multiple]#{$parent} {\n    height: auto;\n  }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n@mixin button-variant($color, $background, $border) {\n  $active-background: darken($background, 10%);\n  $active-border: darken($border, 12%);\n\n  color: $color;\n  background-color: $background;\n  border-color: $border;\n  @include box-shadow($btn-box-shadow);\n\n  @include hover {\n    color: $color;\n    background-color: $active-background;\n        border-color: $active-border;\n  }\n\n  &:focus,\n  &.focus {\n    color: $color;\n    background-color: $active-background;\n        border-color: $active-border;\n  }\n\n  &:active,\n  &.active,\n  .open > &.dropdown-toggle {\n    color: $color;\n    background-color: $active-background;\n        border-color: $active-border;\n    // Remove the gradient for the pressed/active state\n    background-image: none;\n    @include box-shadow($btn-active-box-shadow);\n\n    &:hover,\n    &:focus,\n    &.focus {\n      color: $color;\n      background-color: darken($background, 17%);\n          border-color: darken($border, 25%);\n    }\n  }\n\n  &.disabled,\n  &:disabled {\n    &:focus,\n    &.focus {\n      background-color: $background;\n          border-color: $border;\n    }\n    @include hover {\n      background-color: $background;\n          border-color: $border;\n    }\n  }\n}\n\n@mixin button-outline-variant($color) {\n  color: $color;\n  background-image: none;\n  background-color: transparent;\n  border-color: $color;\n\n  @include hover {\n    color: #fff;\n    background-color: $color;\n        border-color: $color;\n  }\n\n  &:focus,\n  &.focus {\n    color: #fff;\n    background-color: $color;\n        border-color: $color;\n  }\n\n  &:active,\n  &.active,\n  .open > &.dropdown-toggle {\n    color: #fff;\n    background-color: $color;\n        border-color: $color;\n\n    &:hover,\n    &:focus,\n    &.focus {\n      color: #fff;\n      background-color: darken($color, 17%);\n          border-color: darken($color, 25%);\n    }\n  }\n\n  &.disabled,\n  &:disabled {\n    &:focus,\n    &.focus {\n      border-color: lighten($color, 20%);\n    }\n    @include hover {\n      border-color: lighten($color, 20%);\n    }\n  }\n}\n\n// Button sizes\n@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) {\n  padding: $padding-y $padding-x;\n  font-size: $font-size;\n  @include border-radius($border-radius);\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n@mixin nav-divider($color: #e5e5e5) {\n  height: 1px;\n  margin: ($spacer-y / 2) 0;\n  overflow: hidden;\n  background-color: $color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9.\n\n@mixin reset-filter() {\n  filter: \"progid:DXImageTransform.Microsoft.gradient(enabled = false)\";\n}\n","//\n// Base styles\n//\n\n.alert {\n  padding: $alert-padding-y $alert-padding-x;\n  margin-bottom: $spacer-y;\n  border: $alert-border-width solid transparent;\n  @include border-radius($alert-border-radius);\n}\n\n// Headings for larger alerts\n.alert-heading {\n  // Specified to prevent conflicts of changing $headings-color\n  color: inherit;\n}\n\n// Provide class for links that match alerts\n.alert-link {\n  font-weight: $alert-link-font-weight;\n}\n\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissible {\n  padding-right: ($alert-padding-x * 2);\n\n  // Adjust close link position\n  .close {\n    position: relative;\n    top: -.125rem;\n    right: -$alert-padding-x;\n    color: inherit;\n  }\n}\n\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n  @include alert-variant($alert-success-bg, $alert-success-border, $alert-success-text);\n}\n.alert-info {\n  @include alert-variant($alert-info-bg, $alert-info-border, $alert-info-text);\n}\n.alert-warning {\n  @include alert-variant($alert-warning-bg, $alert-warning-border, $alert-warning-text);\n}\n.alert-danger {\n  @include alert-variant($alert-danger-bg, $alert-danger-border, $alert-danger-text);\n}\n",".close {\n  float: right;\n  font-size: ($font-size-base * 1.5);\n  font-weight: $close-font-weight;\n  line-height: 1;\n  color: $close-color;\n  text-shadow: $close-text-shadow;\n  opacity: .2;\n\n  @include hover-focus {\n    color: $close-color;\n    text-decoration: none;\n    cursor: pointer;\n    opacity: .5;\n  }\n}\n\n// Additional properties for button version\n// iOS requires the button element instead of an anchor tag.\n// If you want the anchor version, it requires `href=\"#\"`.\n// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n// scss-lint:disable QualifyingElement\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n// scss-lint:enable QualifyingElement\n","// Base class\n//\n// Kickstart any navigation component with a set of style resets. Works with\n// `